mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 21:18:02 +00:00
[master] Merge branch 'trac4552'
This commit is contained in:
commit
9b79fe005d
@ -2854,6 +2854,35 @@ It is merely echoed by the server
|
||||
|
||||
</section>
|
||||
|
||||
<section id="reservation4-message-fields">
|
||||
<title>Reserving Next Server, Server Hostname and Boot File Name</title>
|
||||
<para>BOOTP/DHCPv4 messages include "siaddr", "sname" and "file" fields.
|
||||
Even though, DHCPv4 includes corresponding options, such as option 66 and
|
||||
option 67, some clients may not support these options. Thus, server
|
||||
administrators often use "siaddr", "sname" and "file" fields instead.</para>
|
||||
|
||||
<para>With Kea, it is possible to make static reservations for these DHCPv4
|
||||
message fields:</para>
|
||||
|
||||
<screen>
|
||||
{
|
||||
"subnet4": [ {
|
||||
"reservations": [
|
||||
{
|
||||
"hw-address": "aa:bb:cc:dd:ee:ff",
|
||||
<userinput>"next-server": "10.1.1.2",
|
||||
"server-hostname": "server-hostname.example.org",
|
||||
"boot-file-name": "/tmp/bootfile.efi"</userinput>
|
||||
} ]
|
||||
} ]
|
||||
}</screen>
|
||||
|
||||
<para>Note that those parameters can be specified in combination with
|
||||
other parameters for a reservation, e.g. reserved IPv4 address. These
|
||||
parameters are optional, i.e. a subset of them can specified, or all of
|
||||
them can be omitted.</para>
|
||||
</section>
|
||||
|
||||
<section id="reservations4-mysql-pgsql">
|
||||
<title>Storing host reservations in MySQL or PostgreSQL</title>
|
||||
|
||||
|
@ -513,6 +513,24 @@
|
||||
"item_type": "string",
|
||||
"item_optional": false,
|
||||
"item_default": "0.0.0.0"
|
||||
},
|
||||
{
|
||||
"item_name": "next-server",
|
||||
"item_type": "string",
|
||||
"item_optional": true,
|
||||
"item_default": "0.0.0.0"
|
||||
},
|
||||
{
|
||||
"item_name": "server-hostname",
|
||||
"item_type": "string",
|
||||
"item_optional": true,
|
||||
"item_default": ""
|
||||
},
|
||||
{
|
||||
"item_name": "boot-file-name",
|
||||
"item_type": "string",
|
||||
"item_optional": true,
|
||||
"item_default": ""
|
||||
} ]
|
||||
}
|
||||
},
|
||||
|
@ -153,6 +153,9 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
|
||||
|
||||
// Check for static reservations.
|
||||
alloc_engine->findReservation(*context_);
|
||||
|
||||
// Set siaddr, sname and file.
|
||||
setReservedMessageFields();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -333,6 +336,27 @@ Dhcpv4Exchange::setHostIdentifiers() {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Exchange::setReservedMessageFields() {
|
||||
ConstHostPtr host = context_->host_;
|
||||
// Nothing to do if host reservations not specified for this client.
|
||||
if (host) {
|
||||
if (!host->getNextServer().isV4Zero()) {
|
||||
resp_->setSiaddr(host->getNextServer());
|
||||
}
|
||||
|
||||
if (!host->getServerHostname().empty()) {
|
||||
resp_->setSname(reinterpret_cast<
|
||||
const uint8_t*>(host->getServerHostname().c_str()));
|
||||
}
|
||||
|
||||
if (!host->getBootFileName().empty()) {
|
||||
resp_->setFile(reinterpret_cast<
|
||||
const uint8_t*>(host->getBootFileName().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
|
||||
|
||||
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
|
||||
@ -1515,12 +1539,6 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up siaddr. Perhaps assignLease is not the best place to call this
|
||||
// as siaddr has nothing to do with a lease, but otherwise we would have
|
||||
// to select subnet twice (performance hit) or update too many functions
|
||||
// at once.
|
||||
/// @todo: move subnet selection to a common code
|
||||
resp->setSiaddr(subnet->getSiaddr());
|
||||
|
||||
// Get the server identifier. It will be used to determine the state
|
||||
// of the client.
|
||||
@ -2635,9 +2653,12 @@ Dhcpv4Srv::vendorClassSpecificProcessing(const Dhcpv4Exchange& ex) {
|
||||
|
||||
if (query->inClass(VENDOR_CLASS_PREFIX + DOCSIS3_CLASS_MODEM)) {
|
||||
|
||||
// Do not override
|
||||
if (rsp->getSiaddr().isV4Zero()) {
|
||||
// Set next-server. This is TFTP server address. Cable modems will
|
||||
// download their configuration from that server.
|
||||
rsp->setSiaddr(subnet->getSiaddr());
|
||||
}
|
||||
|
||||
// Now try to set up file field in DHCPv4 packet. We will just copy
|
||||
// content of the boot-file option, which contains the same information.
|
||||
@ -2664,6 +2685,12 @@ Dhcpv4Srv::vendorClassSpecificProcessing(const Dhcpv4Exchange& ex) {
|
||||
rsp->setSiaddr(IOAddress::IPV4_ZERO_ADDRESS());
|
||||
}
|
||||
|
||||
// Set up siaddr. Do not override siaddr if host specific value or
|
||||
// vendor class specific value present.
|
||||
if (rsp->getSiaddr().isV4Zero()) {
|
||||
rsp->setSiaddr(subnet->getSiaddr());
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,10 @@ private:
|
||||
/// host-reservation-identifiers
|
||||
void setHostIdentifiers();
|
||||
|
||||
/// @brief Sets reserved values of siaddr, sname and file in the
|
||||
/// server's response.
|
||||
void setReservedMessageFields();
|
||||
|
||||
/// @brief Pointer to the allocation engine used by the server.
|
||||
AllocEnginePtr alloc_engine_;
|
||||
/// @brief Pointer to the DHCPv4 message sent by the client.
|
||||
|
@ -23,7 +23,7 @@ namespace test {
|
||||
|
||||
Dhcp4Client::Configuration::Configuration()
|
||||
: routers_(), dns_servers_(), log_servers_(), quotes_servers_(),
|
||||
serverid_("0.0.0.0") {
|
||||
serverid_("0.0.0.0"), siaddr_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -34,6 +34,9 @@ Dhcp4Client::Configuration::reset() {
|
||||
log_servers_.clear();
|
||||
quotes_servers_.clear();
|
||||
serverid_ = asiolink::IOAddress("0.0.0.0");
|
||||
siaddr_ = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
|
||||
sname_.clear();
|
||||
boot_file_name_.clear();
|
||||
lease_ = Lease4();
|
||||
}
|
||||
|
||||
@ -178,6 +181,17 @@ Dhcp4Client::applyConfiguration() {
|
||||
if (opt_vendor) {
|
||||
config_.vendor_suboptions_ = opt_vendor->getOptions();
|
||||
}
|
||||
// siaddr
|
||||
config_.siaddr_ = resp->getSiaddr();
|
||||
// sname
|
||||
OptionBuffer buf = resp->getSname();
|
||||
// sname is a fixed length field holding null terminated string. Use
|
||||
// of c_str() guarantess that only a useful portion (ending with null
|
||||
// character) is assigned.
|
||||
config_.sname_.assign(std::string(buf.begin(), buf.end()).c_str());
|
||||
// (boot)file
|
||||
buf = resp->getFile();
|
||||
config_.boot_file_name_.assign(std::string(buf.begin(), buf.end()).c_str());
|
||||
// Server Identifier
|
||||
OptionCustomPtr opt_serverid = boost::dynamic_pointer_cast<
|
||||
OptionCustom>(resp->getOption(DHO_DHCP_SERVER_IDENTIFIER));
|
||||
|
@ -81,6 +81,12 @@ public:
|
||||
/// @brief Holds server id of the server which responded to the client's
|
||||
/// request.
|
||||
asiolink::IOAddress serverid_;
|
||||
/// @brief Holds returned siaddr.
|
||||
asiolink::IOAddress siaddr_;
|
||||
/// @brief Holds returned sname.
|
||||
std::string sname_;
|
||||
/// @brief Holds returned (boot)file.
|
||||
std::string boot_file_name_;
|
||||
|
||||
/// @brief Constructor.
|
||||
Configuration();
|
||||
|
@ -71,6 +71,15 @@ namespace {
|
||||
/// - The same as configuration 4, but using the following order of
|
||||
/// host-reservation-identifiers: duid, circuit-id, hw-address.
|
||||
///
|
||||
/// - Configuration 6:
|
||||
/// - This configuration provides reservations for next-server,
|
||||
/// server-hostname and boot-file-name value.
|
||||
/// - 1 subnet: 10.0.0.0/24
|
||||
/// - 1 reservation for this subnet:
|
||||
/// - Client's HW address: aa:bb:cc:dd:ee:ff
|
||||
/// - next-server = 10.0.0.7
|
||||
/// - server name = "some-name.example.org"
|
||||
/// - boot-file-name = "bootfile.efi"
|
||||
const char* DORA_CONFIGS[] = {
|
||||
// Configuration 0
|
||||
"{ \"interfaces-config\": {"
|
||||
@ -233,6 +242,26 @@ const char* DORA_CONFIGS[] = {
|
||||
" }"
|
||||
" ]"
|
||||
"} ]"
|
||||
"}",
|
||||
|
||||
// Configuration 6
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"valid-lifetime\": 600,"
|
||||
"\"next-server\": \"10.0.0.1\","
|
||||
"\"subnet4\": [ { "
|
||||
" \"subnet\": \"10.0.0.0/24\", "
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"reservations\": [ "
|
||||
" {"
|
||||
" \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
|
||||
" \"next-server\": \"10.0.0.7\","
|
||||
" \"server-hostname\": \"some-name.example.org\","
|
||||
" \"boot-file-name\": \"bootfile.efi\""
|
||||
" }"
|
||||
" ]"
|
||||
"} ]"
|
||||
"}"
|
||||
};
|
||||
|
||||
@ -989,6 +1018,32 @@ TEST_F(DORATest, changingHWAddress) {
|
||||
EXPECT_FALSE(client.config_.lease_.client_id_);
|
||||
}
|
||||
|
||||
// This test verifies that the server assigns reserved values for the
|
||||
// siaddr, sname and file fields carried within DHCPv4 message.
|
||||
TEST_F(DORATest, messageFieldsReservations) {
|
||||
// Client has a reservation.
|
||||
Dhcp4Client client(Dhcp4Client::SELECTING);
|
||||
// Set explicit HW address so as it matches the reservation in the
|
||||
// configuration used below.
|
||||
client.setHWAddress("aa:bb:cc:dd:ee:ff");
|
||||
// Configure DHCP server.
|
||||
configure(DORA_CONFIGS[6], *client.getServer());
|
||||
// Client performs 4-way exchange and should obtain a reserved
|
||||
// address and fixed fields.
|
||||
ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
|
||||
IOAddress>(new IOAddress("0.0.0.0"))));
|
||||
// Make sure that the server responded.
|
||||
ASSERT_TRUE(client.getContext().response_);
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
// Make sure that the server has responded with DHCPACK.
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
|
||||
// Check that the reserved values have been assigned.
|
||||
EXPECT_EQ("10.0.0.7", client.config_.siaddr_.toText());
|
||||
EXPECT_EQ("some-name.example.org", client.config_.sname_);
|
||||
EXPECT_EQ("bootfile.efi", client.config_.boot_file_name_);
|
||||
}
|
||||
|
||||
// This test checks the following scenario:
|
||||
// 1. Client A performs 4-way exchange and obtains a lease from the dynamic pool.
|
||||
// 2. Reservation is created for the client A using an address out of the dynamic
|
||||
|
@ -39,6 +39,16 @@ namespace {
|
||||
/// - Domain Name Server option present: 192.0.2.202, 192.0.2.203.
|
||||
/// - Log Servers option present: 192.0.2.200 and 192.0.2.201
|
||||
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
|
||||
///
|
||||
/// - Configuration 2:
|
||||
/// - This configuration provides reservations for next-server,
|
||||
/// server-hostname and boot-file-name value.
|
||||
/// - 1 subnet: 192.0.2.0/24
|
||||
/// - 1 reservation for this subnet:
|
||||
/// - Client's HW address: aa:bb:cc:dd:ee:ff
|
||||
/// - next-server = 10.0.0.7
|
||||
/// - server name = "some-name.example.org"
|
||||
/// - boot-file-name = "bootfile.efi"
|
||||
const char* INFORM_CONFIGS[] = {
|
||||
// Configuration 0
|
||||
"{ \"interfaces-config\": {"
|
||||
@ -91,7 +101,26 @@ const char* INFORM_CONFIGS[] = {
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}",
|
||||
|
||||
// Configuration 2
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"valid-lifetime\": 600,"
|
||||
"\"next-server\": \"10.0.0.1\","
|
||||
"\"subnet4\": [ { "
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"reservations\": [ "
|
||||
" {"
|
||||
" \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
|
||||
" \"next-server\": \"10.0.0.7\","
|
||||
" \"server-hostname\": \"some-name.example.org\","
|
||||
" \"boot-file-name\": \"bootfile.efi\""
|
||||
" }"
|
||||
" ]"
|
||||
"} ]"
|
||||
"}",
|
||||
};
|
||||
|
||||
/// @brief Test fixture class for testing DHCPINFORM.
|
||||
@ -364,6 +393,32 @@ TEST_F(InformTest, relayedClientNoCiaddr) {
|
||||
EXPECT_EQ("192.0.2.203", client.config_.dns_servers_[1].toText());
|
||||
}
|
||||
|
||||
// This test verifies that the server assigns reserved values for the
|
||||
// siaddr, sname and file fields carried within DHCPv4 message.
|
||||
TEST_F(InformTest, messageFieldsReservations) {
|
||||
// Client has a reservation.
|
||||
Dhcp4Client client(Dhcp4Client::SELECTING);
|
||||
// Message is relayed.
|
||||
client.useRelay();
|
||||
// Set explicit HW address so as it matches the reservation in the
|
||||
// configuration used below.
|
||||
client.setHWAddress("aa:bb:cc:dd:ee:ff");
|
||||
// Configure DHCP server.
|
||||
configure(INFORM_CONFIGS[2], *client.getServer());
|
||||
// Client sends DHCPINFORM and should receive reserved fields.
|
||||
ASSERT_NO_THROW(client.doInform());
|
||||
// Make sure that the server responded.
|
||||
ASSERT_TRUE(client.getContext().response_);
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
// Make sure that the server has responded with DHCPACK.
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
|
||||
// Check that the reserved values have been assigned.
|
||||
EXPECT_EQ("10.0.0.7", client.config_.siaddr_.toText());
|
||||
EXPECT_EQ("some-name.example.org", client.config_.sname_);
|
||||
EXPECT_EQ("bootfile.efi", client.config_.boot_file_name_);
|
||||
}
|
||||
|
||||
/// This test verifies that after a client completes its INFORM exchange,
|
||||
/// appropriate statistics are updated.
|
||||
TEST_F(InformTest, statisticsInform) {
|
||||
|
@ -572,10 +572,13 @@ CfgHosts::add4(const HostPtr& host) {
|
||||
DuidPtr duid = host->getDuid();
|
||||
|
||||
// There should be at least one resource reserved: hostname, IPv4
|
||||
// address, IPv6 address or prefix.
|
||||
// address, siaddr, sname, file or IPv6 address or prefix.
|
||||
if (host->getHostname().empty() &&
|
||||
(host->getIPv4Reservation().isV4Zero()) &&
|
||||
(!host->hasIPv6Reservation()) &&
|
||||
!host->hasIPv6Reservation() &&
|
||||
host->getNextServer().isV4Zero() &&
|
||||
host->getServerHostname().empty() &&
|
||||
host->getBootFileName().empty() &&
|
||||
host->getCfgOption4()->empty() &&
|
||||
host->getCfgOption6()->empty()) {
|
||||
std::ostringstream s;
|
||||
|
@ -5,6 +5,7 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcpsrv/host.h>
|
||||
#include <util/encode/hex.h>
|
||||
#include <util/strutil.h>
|
||||
@ -74,14 +75,20 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
|
||||
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);
|
||||
@ -90,6 +97,11 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
|
||||
// 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,
|
||||
@ -97,14 +109,19 @@ 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);
|
||||
@ -113,6 +130,11 @@ Host::Host(const std::string& identifier, const std::string& 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>&
|
||||
@ -339,6 +361,37 @@ Host::addClientClassInternal(ClientClasses& classes,
|
||||
}
|
||||
}
|
||||
|
||||
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.isV4Bcast()) {
|
||||
isc_throw(isc::BadValue, "invalid next server address '"
|
||||
<< next_server << "'");
|
||||
}
|
||||
|
||||
next_server_ = next_server;
|
||||
}
|
||||
|
||||
void
|
||||
Host::setServerHostname(const std::string& server_host_name) {
|
||||
if (server_host_name.size() > Pkt4::MAX_SNAME_LEN - 1) {
|
||||
isc_throw(isc::BadValue, "server hostname length must not exceed "
|
||||
<< (Pkt4::MAX_SNAME_LEN - 1));
|
||||
}
|
||||
server_host_name_ = server_host_name;
|
||||
}
|
||||
|
||||
void
|
||||
Host::setBootFileName(const std::string& boot_file_name) {
|
||||
if (boot_file_name.size() > Pkt4::MAX_FILE_LEN - 1) {
|
||||
isc_throw(isc::BadValue, "boot file length must not exceed "
|
||||
<< (Pkt4::MAX_FILE_LEN - 1));
|
||||
}
|
||||
boot_file_name_ = boot_file_name;
|
||||
}
|
||||
|
||||
std::string
|
||||
Host::toText() const {
|
||||
std::ostringstream s;
|
||||
@ -363,6 +416,16 @@ Host::toText() const {
|
||||
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)";
|
||||
|
||||
|
@ -214,6 +214,9 @@ public:
|
||||
/// 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.
|
||||
@ -223,7 +226,10 @@ public:
|
||||
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.
|
||||
///
|
||||
@ -258,6 +264,9 @@ public:
|
||||
/// 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.
|
||||
@ -266,7 +275,10 @@ public:
|
||||
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.
|
||||
///
|
||||
@ -449,6 +461,43 @@ public:
|
||||
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 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.
|
||||
///
|
||||
/// @throw BadValue if hostname is longer than 63 bytes.
|
||||
void setServerHostname(const std::string& server_host_name);
|
||||
|
||||
/// @brief Returns value of server hostname (sname).
|
||||
const 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.
|
||||
///
|
||||
/// @throw BadValue if boot file name is longer than 128 bytes.
|
||||
void setBootFileName(const std::string& boot_file_name);
|
||||
|
||||
/// @brief Returns value of boot file name (file).
|
||||
const std::string& getBootFileName() const {
|
||||
return (boot_file_name_);
|
||||
}
|
||||
|
||||
/// @brief Returns pointer to the DHCPv4 option data configuration for
|
||||
/// this host.
|
||||
///
|
||||
@ -527,6 +576,12 @@ private:
|
||||
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)
|
||||
|
@ -63,6 +63,12 @@ const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192;
|
||||
/// @brief Maximum length of option space name.
|
||||
const size_t OPTION_SPACE_MAX_LEN = 128;
|
||||
|
||||
/// @brief Maximum length of the server hostname.
|
||||
const size_t SERVER_HOSTNAME_MAX_LEN = 64;
|
||||
|
||||
/// @brief Maximum length of the boot file name.
|
||||
const size_t BOOT_FILE_NAME_MAX_LEN = 128;
|
||||
|
||||
/// @brief Numeric value representing last supported identifier.
|
||||
///
|
||||
/// This value is used to validate whether the identifier type stored in
|
||||
@ -81,7 +87,7 @@ class MySqlHostExchange {
|
||||
private:
|
||||
|
||||
/// @brief Number of columns returned for SELECT queries send by this class.
|
||||
static const size_t HOST_COLUMNS = 9;
|
||||
static const size_t HOST_COLUMNS = 12;
|
||||
|
||||
public:
|
||||
|
||||
@ -99,17 +105,25 @@ public:
|
||||
dhcp4_subnet_id_(0), dhcp6_subnet_id_(0), ipv4_address_(0),
|
||||
hostname_length_(0), dhcp4_client_classes_length_(0),
|
||||
dhcp6_client_classes_length_(0),
|
||||
dhcp4_next_server_(0),
|
||||
dhcp4_server_hostname_length_(0),
|
||||
dhcp4_boot_file_name_length_(0),
|
||||
dhcp4_subnet_id_null_(MLM_FALSE),
|
||||
dhcp6_subnet_id_null_(MLM_FALSE),
|
||||
ipv4_address_null_(MLM_FALSE), hostname_null_(MLM_FALSE),
|
||||
dhcp4_client_classes_null_(MLM_FALSE),
|
||||
dhcp6_client_classes_null_(MLM_FALSE) {
|
||||
dhcp6_client_classes_null_(MLM_FALSE),
|
||||
dhcp4_next_server_null_(MLM_FALSE),
|
||||
dhcp4_server_hostname_null_(MLM_FALSE),
|
||||
dhcp4_boot_file_name_null_(MLM_FALSE) {
|
||||
|
||||
// Fill arrays with 0 so as they don't include any garbage.
|
||||
memset(dhcp_identifier_buffer_, 0, sizeof(dhcp_identifier_buffer_));
|
||||
memset(hostname_, 0, sizeof(hostname_));
|
||||
memset(dhcp4_client_classes_, 0, sizeof(dhcp4_client_classes_));
|
||||
memset(dhcp6_client_classes_, 0, sizeof(dhcp6_client_classes_));
|
||||
memset(dhcp4_server_hostname_, 0, sizeof(dhcp4_server_hostname_));
|
||||
memset(dhcp4_boot_file_name_, 0, sizeof(dhcp4_boot_file_name_));
|
||||
|
||||
// Set the column names for use by this class. This only comprises
|
||||
// names used by the MySqlHostExchange class. Derived classes will
|
||||
@ -123,8 +137,11 @@ public:
|
||||
columns_[6] = "hostname";
|
||||
columns_[7] = "dhcp4_client_classes";
|
||||
columns_[8] = "dhcp6_client_classes";
|
||||
columns_[9] = "dhcp4_next_server";
|
||||
columns_[10] = "dhcp4_server_hostname";
|
||||
columns_[11] = "dhcp4_boot_file_name";
|
||||
|
||||
BOOST_STATIC_ASSERT(8 < HOST_COLUMNS);
|
||||
BOOST_STATIC_ASSERT(11 < HOST_COLUMNS);
|
||||
};
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
@ -307,6 +324,32 @@ public:
|
||||
bind_[8].buffer = dhcp6_client_classes_;
|
||||
bind_[8].buffer_length = classes6_txt.length();
|
||||
|
||||
// ipv4_address : INT UNSIGNED NULL
|
||||
// The address in the Host structure is an IOAddress object. Convert
|
||||
// this to an integer for storage.
|
||||
dhcp4_next_server_ = static_cast<uint32_t>(host->getNextServer());
|
||||
bind_[9].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[9].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
|
||||
bind_[9].is_unsigned = MLM_TRUE;
|
||||
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
|
||||
// reasons, see memset() above
|
||||
|
||||
// dhcp4_server_hostname
|
||||
bind_[10].buffer_type = MYSQL_TYPE_STRING;
|
||||
std::string server_hostname = host->getServerHostname();
|
||||
strncpy(dhcp4_server_hostname_, server_hostname.c_str(),
|
||||
SERVER_HOSTNAME_MAX_LEN - 1);
|
||||
bind_[10].buffer = dhcp4_server_hostname_;
|
||||
bind_[10].buffer_length = server_hostname.length();
|
||||
|
||||
// dhcp4_boot_file_name
|
||||
bind_[11].buffer_type = MYSQL_TYPE_STRING;
|
||||
std::string boot_file_name = host->getBootFileName();
|
||||
strncpy(dhcp4_boot_file_name_, boot_file_name.c_str(),
|
||||
BOOT_FILE_NAME_MAX_LEN - 1);
|
||||
bind_[11].buffer = dhcp4_boot_file_name_;
|
||||
bind_[11].buffer_length = boot_file_name.length();
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DbOperationError,
|
||||
"Could not create bind array from Host: "
|
||||
@ -399,6 +442,31 @@ public:
|
||||
bind_[8].length = &dhcp6_client_classes_length_;
|
||||
bind_[8].is_null = &dhcp6_client_classes_null_;
|
||||
|
||||
// dhcp4_next_server
|
||||
dhcp4_next_server_null_ = MLM_FALSE;
|
||||
bind_[9].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[9].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
|
||||
bind_[9].is_unsigned = MLM_TRUE;
|
||||
bind_[9].is_null = &dhcp4_next_server_null_;
|
||||
|
||||
// dhcp4_server_hostname
|
||||
dhcp4_server_hostname_null_ = MLM_FALSE;
|
||||
dhcp4_server_hostname_length_ = sizeof(dhcp4_server_hostname_);
|
||||
bind_[10].buffer_type = MYSQL_TYPE_STRING;
|
||||
bind_[10].buffer = reinterpret_cast<char*>(dhcp4_server_hostname_);
|
||||
bind_[10].buffer_length = dhcp4_server_hostname_length_;
|
||||
bind_[10].length = &dhcp4_server_hostname_length_;
|
||||
bind_[10].is_null = &dhcp4_server_hostname_null_;
|
||||
|
||||
// dhcp4_boot_file_name
|
||||
dhcp4_boot_file_name_null_ = MLM_FALSE;
|
||||
dhcp4_boot_file_name_length_ = sizeof(dhcp4_boot_file_name_);
|
||||
bind_[11].buffer_type = MYSQL_TYPE_STRING;
|
||||
bind_[11].buffer = reinterpret_cast<char*>(dhcp4_boot_file_name_);
|
||||
bind_[11].buffer_length = dhcp4_boot_file_name_length_;
|
||||
bind_[11].length = &dhcp4_boot_file_name_length_;
|
||||
bind_[11].is_null = &dhcp4_boot_file_name_null_;
|
||||
|
||||
// Add the error flags
|
||||
setErrorIndicators(bind_, error_);
|
||||
|
||||
@ -468,10 +536,32 @@ public:
|
||||
dhcp6_client_classes_length_);
|
||||
}
|
||||
|
||||
// Set next server value (siaddr) if non NULL value returned.
|
||||
asiolink::IOAddress next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
|
||||
if (dhcp4_next_server_null_ == MLM_FALSE) {
|
||||
next_server = asiolink::IOAddress(dhcp4_next_server_);
|
||||
}
|
||||
|
||||
// Set server hostname (sname) if non NULL value returned.
|
||||
std::string dhcp4_server_hostname;
|
||||
if (dhcp4_server_hostname_null_ == MLM_FALSE) {
|
||||
dhcp4_server_hostname = std::string(dhcp4_server_hostname_,
|
||||
dhcp4_server_hostname_length_);
|
||||
}
|
||||
|
||||
// Set boot file name (file) if non NULL value returned.
|
||||
std::string dhcp4_boot_file_name;
|
||||
if (dhcp4_boot_file_name_null_ == MLM_FALSE) {
|
||||
dhcp4_boot_file_name = std::string(dhcp4_boot_file_name_,
|
||||
dhcp4_boot_file_name_length_);
|
||||
}
|
||||
|
||||
// Create and return Host object from the data gathered.
|
||||
HostPtr h(new Host(dhcp_identifier_buffer_, dhcp_identifier_length_,
|
||||
type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation,
|
||||
hostname, dhcp4_client_classes, dhcp6_client_classes));
|
||||
hostname, dhcp4_client_classes, dhcp6_client_classes,
|
||||
next_server, dhcp4_server_hostname,
|
||||
dhcp4_boot_file_name));
|
||||
h->setHostId(host_id_);
|
||||
|
||||
return (h);
|
||||
@ -580,6 +670,21 @@ private:
|
||||
/// client classes.
|
||||
unsigned long dhcp6_client_classes_length_;
|
||||
|
||||
/// Next server address (siaddr).
|
||||
uint32_t dhcp4_next_server_;
|
||||
|
||||
/// Server hostname (sname).
|
||||
char dhcp4_server_hostname_[SERVER_HOSTNAME_MAX_LEN];
|
||||
|
||||
/// A length of the string holding server hostname.
|
||||
unsigned long dhcp4_server_hostname_length_;
|
||||
|
||||
/// Boot file name (file).
|
||||
char dhcp4_boot_file_name_[BOOT_FILE_NAME_MAX_LEN];
|
||||
|
||||
/// A length of the string holding boot file name.
|
||||
unsigned long dhcp4_boot_file_name_length_;
|
||||
|
||||
/// @name Boolean values indicating if values of specific columns in
|
||||
/// the database are NULL.
|
||||
//@{
|
||||
@ -603,6 +708,15 @@ private:
|
||||
/// NULL.
|
||||
my_bool dhcp6_client_classes_null_;
|
||||
|
||||
/// Boolean flag indicating if the value of next server is NULL.
|
||||
my_bool dhcp4_next_server_null_;
|
||||
|
||||
/// Boolean flag indicating if the value of server hostname is NULL.
|
||||
my_bool dhcp4_server_hostname_null_;
|
||||
|
||||
/// Boolean flag indicating if the value of boot file name is NULL.
|
||||
my_bool dhcp4_boot_file_name_null_;
|
||||
|
||||
//@}
|
||||
|
||||
};
|
||||
@ -1817,6 +1931,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
|
||||
"h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
|
||||
"o4.persistent, "
|
||||
"o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
|
||||
@ -1840,6 +1955,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
"o.persistent "
|
||||
"FROM hosts AS h "
|
||||
@ -1855,6 +1971,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
"o.persistent "
|
||||
"FROM hosts AS h "
|
||||
@ -1872,6 +1989,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
|
||||
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
"o.persistent, "
|
||||
"r.reservation_id, r.address, r.prefix_len, r.type, "
|
||||
@ -1893,6 +2011,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
"o.persistent "
|
||||
"FROM hosts AS h "
|
||||
@ -1912,6 +2031,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
|
||||
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
"h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
"o.persistent, "
|
||||
"r.reservation_id, r.address, r.prefix_len, r.type, "
|
||||
@ -1934,8 +2054,9 @@ TaggedStatementArray tagged_statements = { {
|
||||
{MySqlHostDataSourceImpl::INSERT_HOST,
|
||||
"INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
|
||||
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
"dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
|
||||
"dhcp4_client_classes, dhcp6_client_classes, dhcp4_next_server, "
|
||||
"dhcp4_server_hostname, dhcp4_boot_file_name) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
|
||||
|
||||
// Inserts a single IPv6 reservation into 'reservations' table.
|
||||
{MySqlHostDataSourceImpl::INSERT_V6_RESRV,
|
||||
|
@ -49,6 +49,9 @@ getSupportedParams4(const bool identifiers_only = false) {
|
||||
params_set.insert("hostname");
|
||||
params_set.insert("ip-address");
|
||||
params_set.insert("option-data");
|
||||
params_set.insert("next-server");
|
||||
params_set.insert("server-hostname");
|
||||
params_set.insert("boot-file-name");
|
||||
}
|
||||
return (identifiers_only ? identifiers_set : params_set);
|
||||
}
|
||||
@ -120,7 +123,6 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) {
|
||||
|
||||
} else if (element.first == "hostname") {
|
||||
hostname = element.second->stringValue();
|
||||
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
// Append line number where the error occurred.
|
||||
@ -207,7 +209,16 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) {
|
||||
if (element.first == "ip-address") {
|
||||
host_->setIPv4Reservation(IOAddress(element.second->
|
||||
stringValue()));
|
||||
} else if (element.first == "next-server") {
|
||||
host_->setNextServer(IOAddress(element.second->stringValue()));
|
||||
|
||||
} else if (element.first == "server-hostname") {
|
||||
host_->setServerHostname(element.second->stringValue());
|
||||
|
||||
} else if (element.first == "boot-file-name") {
|
||||
host_->setBootFileName(element.second->stringValue());
|
||||
}
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
// Append line number where the error occurred.
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
|
@ -73,8 +73,11 @@ private:
|
||||
static const int HOSTNAME_COL = 6;
|
||||
static const int DHCP4_CLIENT_CLASSES_COL = 7;
|
||||
static const int DHCP6_CLIENT_CLASSES_COL = 8;
|
||||
static const int DHCP4_NEXT_SERVER_COL = 9;
|
||||
static const int DHCP4_SERVER_HOSTNAME_COL = 10;
|
||||
static const int DHCP4_BOOT_FILE_NAME_COL = 11;
|
||||
/// @brief Number of columns returned for SELECT queries send by this class.
|
||||
static const size_t HOST_COLUMNS = 9;
|
||||
static const size_t HOST_COLUMNS = 12;
|
||||
|
||||
public:
|
||||
|
||||
@ -99,8 +102,11 @@ public:
|
||||
columns_[HOSTNAME_COL] = "hostname";
|
||||
columns_[DHCP4_CLIENT_CLASSES_COL] = "dhcp4_client_classes";
|
||||
columns_[DHCP6_CLIENT_CLASSES_COL] = "dhcp6_client_classes";
|
||||
columns_[DHCP4_NEXT_SERVER_COL] = "dhcp4_next_server";
|
||||
columns_[DHCP4_SERVER_HOSTNAME_COL] = "dhcp4_server_hostname";
|
||||
columns_[DHCP4_BOOT_FILE_NAME_COL] = "dhcp4_boot_file_name";
|
||||
|
||||
BOOST_STATIC_ASSERT(8 < HOST_COLUMNS);
|
||||
BOOST_STATIC_ASSERT(11 < HOST_COLUMNS);
|
||||
};
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
@ -186,7 +192,7 @@ public:
|
||||
bind_array->add(host->getIPv6SubnetID());
|
||||
|
||||
// ipv4_address : BIGINT NULL
|
||||
bind_array->add(host->getIPv4Reservation());
|
||||
bind_array->add((host->getIPv4Reservation()));
|
||||
|
||||
// hostname : VARCHAR(255) NULL
|
||||
bind_array->add(host->getHostname());
|
||||
@ -197,6 +203,16 @@ public:
|
||||
|
||||
// dhcp6_client_classes : VARCHAR(255) NULL
|
||||
bind_array->addTempString(host->getClientClasses6().toText(","));
|
||||
|
||||
// dhcp4_next_server : BIGINT NULL
|
||||
bind_array->add((host->getNextServer()));
|
||||
|
||||
// dhcp4_server_hostname : VARCHAR(64)
|
||||
bind_array->add(host->getServerHostname());
|
||||
|
||||
// dhcp4_boot_file_name : VARCHAR(128)
|
||||
bind_array->add(host->getBootFileName());
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
host_.reset();
|
||||
isc_throw(DbOperationError,
|
||||
@ -296,13 +312,28 @@ public:
|
||||
std::string dhcp6_client_classes;
|
||||
getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
|
||||
|
||||
// dhcp4_next_server : BIGINT NULL
|
||||
uint32_t dhcp4_next_server_as_uint32;
|
||||
getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
|
||||
isc::asiolink::IOAddress dhcp4_next_server(dhcp4_next_server_as_uint32);
|
||||
|
||||
// dhcp4_server_hostname : VARCHAR(64)
|
||||
std::string dhcp4_server_hostname;
|
||||
getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
|
||||
|
||||
// dhcp4_boot_file_name : VARCHAR(128)
|
||||
std::string dhcp4_boot_file_name;
|
||||
getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
|
||||
|
||||
// Finally, attempt to create the new host.
|
||||
HostPtr host;
|
||||
try {
|
||||
host.reset(new Host(identifier_value, identifier_len,
|
||||
identifier_type, dhcp4_subnet_id,
|
||||
dhcp6_subnet_id, ipv4_reservation, hostname,
|
||||
dhcp4_client_classes, dhcp6_client_classes));
|
||||
dhcp4_client_classes, dhcp6_client_classes,
|
||||
dhcp4_next_server, dhcp4_server_hostname,
|
||||
dhcp4_boot_file_name));
|
||||
|
||||
host->setHostId(host_id);
|
||||
} catch (const isc::Exception& ex) {
|
||||
@ -1302,6 +1333,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
|
||||
" h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
|
||||
" o4.persistent, "
|
||||
" o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
|
||||
@ -1323,8 +1355,9 @@ TaggedStatementArray tagged_statements = { {
|
||||
{ OID_INT8 }, "get_host_addr",
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, o.option_id, o.code, "
|
||||
" o.value, o.formatted_value, o.space, o.persistent "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent "
|
||||
"FROM hosts AS h "
|
||||
"LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
|
||||
"WHERE ipv4_address = $1 "
|
||||
@ -1340,8 +1373,9 @@ TaggedStatementArray tagged_statements = { {
|
||||
"get_host_subid4_dhcpid",
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, o.option_id, o.code, "
|
||||
" o.value, o.formatted_value, o.space, o.persistent "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent "
|
||||
"FROM hosts AS h "
|
||||
"LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
|
||||
"WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
|
||||
@ -1360,6 +1394,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
|
||||
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
" o.persistent, "
|
||||
" r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
|
||||
@ -1381,8 +1416,9 @@ TaggedStatementArray tagged_statements = { {
|
||||
"get_host_subid_addr",
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, o.option_id, o.code, "
|
||||
" o.value, o.formatted_value, o.space, o.persistent "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent "
|
||||
"FROM hosts AS h "
|
||||
"LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
|
||||
"WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
|
||||
@ -1403,6 +1439,7 @@ TaggedStatementArray tagged_statements = { {
|
||||
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
|
||||
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
|
||||
" h.dhcp4_client_classes, h.dhcp6_client_classes, "
|
||||
" h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
|
||||
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
|
||||
" o.persistent, "
|
||||
" r.reservation_id, r.address, r.prefix_len, r.type, "
|
||||
@ -1426,15 +1463,16 @@ TaggedStatementArray tagged_statements = { {
|
||||
|
||||
// PgSqlHostDataSourceImpl::INSERT_HOST
|
||||
// Inserts a host into the 'hosts' table. Returns the inserted host id.
|
||||
{8,
|
||||
{11,
|
||||
{ OID_BYTEA, OID_INT2,
|
||||
OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
|
||||
OID_VARCHAR, OID_VARCHAR },
|
||||
"insert_host",
|
||||
"INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
|
||||
" dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
" dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"
|
||||
" dhcp4_client_classes, dhcp6_client_classes, "
|
||||
" dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING host_id"
|
||||
},
|
||||
|
||||
//PgSqlHostDataSourceImpl::INSERT_V6_RESRV
|
||||
|
@ -242,6 +242,9 @@ void GenericHostDataSourceTest::compareHosts(const ConstHostPtr& host1,
|
||||
EXPECT_EQ(host1->getIPv6SubnetID(), host2->getIPv6SubnetID());
|
||||
EXPECT_EQ(host1->getIPv4Reservation(), host2->getIPv4Reservation());
|
||||
EXPECT_EQ(host1->getHostname(), host2->getHostname());
|
||||
EXPECT_EQ(host1->getNextServer(), host2->getNextServer());
|
||||
EXPECT_EQ(host1->getServerHostname(), host2->getServerHostname());
|
||||
EXPECT_EQ(host1->getBootFileName(), host2->getBootFileName());
|
||||
|
||||
// Compare IPv6 reservations
|
||||
compareReservations6(host1->getIPv6Reservations(),
|
||||
@ -1360,6 +1363,67 @@ GenericHostDataSourceTest::testMultipleClientClassesBoth() {
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
}
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::testMessageFields4() {
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
// Create the Host object.
|
||||
HostPtr host = initializeHost4("192.0.2.5", Host::IDENT_HWADDR);
|
||||
// And assign values for DHCPv4 message fields.
|
||||
ASSERT_NO_THROW({
|
||||
host->setNextServer(IOAddress("10.1.1.1"));
|
||||
host->setServerHostname("server-name.example.org");
|
||||
host->setBootFileName("bootfile.efi");
|
||||
});
|
||||
|
||||
// Add the host.
|
||||
ASSERT_NO_THROW(hdsptr_->add(host));
|
||||
|
||||
// Subnet id will be used in quries to the database.
|
||||
SubnetID subnet_id = host->getIPv4SubnetID();
|
||||
|
||||
// Fetch the host via:
|
||||
// getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
|
||||
ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getHWAddress());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
// Fetch the host via:
|
||||
// getAll(const Host::IdentifierType, const uint8_t* identifier_begin,
|
||||
// const size_t identifier_len) const;
|
||||
hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
// Fetch the host via
|
||||
// getAll4(const asiolink::IOAddress& address) const;
|
||||
hosts_by_id = hdsptr_->getAll4(IOAddress("192.0.2.5"));
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
// Fetch the host via
|
||||
// get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
|
||||
// const DuidPtr& duid = DuidPtr()) const;
|
||||
ConstHostPtr from_hds = hdsptr_->get4(subnet_id, host->getHWAddress());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
// Fetch the host via
|
||||
// get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
// const uint8_t* identifier_begin, const size_t identifier_len) const;
|
||||
from_hds = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
// Fetch the host via:
|
||||
// get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
|
||||
from_hds = hdsptr_->get4(subnet_id, IOAddress("192.0.2.5"));
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
}
|
||||
|
||||
}; // namespace test
|
||||
}; // namespace dhcp
|
||||
}; // namespace isc
|
||||
|
@ -513,6 +513,13 @@ public:
|
||||
///
|
||||
void testMultipleClientClassesBoth();
|
||||
|
||||
/// @brief Test that siaddr, sname, file fields can be retrieved
|
||||
/// from a database for a host.
|
||||
///
|
||||
/// Uses gtest macros to report failures.
|
||||
///
|
||||
void testMessageFields4();
|
||||
|
||||
/// @brief Returns DUID with identical content as specified HW address
|
||||
///
|
||||
/// This method does not have any sense in real life and is only useful
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -299,6 +300,71 @@ TEST_F(HostReservationParserTest, dhcp4NoHostname) {
|
||||
EXPECT_TRUE(hosts[0]->getHostname().empty());
|
||||
}
|
||||
|
||||
// This test verifies that the parser can parse reservation entry
|
||||
// containing next-server, server-hostname and boot-file-name values for
|
||||
// DHCPv4 message fields.
|
||||
TEST_F(HostReservationParserTest, dhcp4MessageFields) {
|
||||
std::string config = "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"next-server\": \"192.0.2.11\","
|
||||
"\"server-hostname\": \"some-name.example.org\","
|
||||
"\"boot-file-name\": \"/tmp/some-file.efi\" }";
|
||||
|
||||
ElementPtr config_element = Element::fromJSON(config);
|
||||
|
||||
HostReservationParser4 parser(SubnetID(10));
|
||||
ASSERT_NO_THROW(parser.build(config_element));
|
||||
|
||||
CfgHostsPtr cfg_hosts = CfgMgr::instance().getStagingCfg()->getCfgHosts();
|
||||
HostCollection hosts;
|
||||
ASSERT_NO_THROW(hosts = cfg_hosts->getAll(Host::IDENT_HWADDR,
|
||||
&hwaddr_->hwaddr_[0],
|
||||
hwaddr_->hwaddr_.size()));
|
||||
|
||||
ASSERT_EQ(1, hosts.size());
|
||||
|
||||
EXPECT_EQ(10, hosts[0]->getIPv4SubnetID());
|
||||
EXPECT_EQ("192.0.2.11", hosts[0]->getNextServer().toText());
|
||||
EXPECT_EQ("some-name.example.org", hosts[0]->getServerHostname());
|
||||
EXPECT_EQ("/tmp/some-file.efi", hosts[0]->getBootFileName());
|
||||
}
|
||||
|
||||
// This test verifies that the invalid value of the next server is rejected.
|
||||
TEST_F(HostReservationParserTest, invalidNextServer) {
|
||||
// Invalid IPv4 address.
|
||||
std::string config = "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"next-server\": \"192.0.2.foo\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
|
||||
// Broadcast address.
|
||||
config = "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"next-server\": \"255.255.255.255\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
|
||||
// IPv6 address.
|
||||
config = "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"next-server\": \"2001:db8:1::1\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
}
|
||||
|
||||
// This test verifies that the invalid server hostname is rejected.
|
||||
TEST_F(HostReservationParserTest, invalidServerHostname) {
|
||||
std::ostringstream config;
|
||||
config << "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"server-hostname\": \"";
|
||||
config << std::string(64, 'a');
|
||||
config << "\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config.str());
|
||||
}
|
||||
|
||||
// This test verifies that the invalid boot file name is rejected.
|
||||
TEST_F(HostReservationParserTest, invalidBootFileName) {
|
||||
std::ostringstream config;
|
||||
config << "{ \"hw-address\": \"1:2:3:4:5:6\","
|
||||
"\"boot-file-name\": \"";
|
||||
config << std::string(128, 'a');
|
||||
config << "\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config.str());
|
||||
}
|
||||
|
||||
// This test verifies that the configuration parser for host reservations
|
||||
// throws an exception when IPv6 address is specified for IPv4 address
|
||||
@ -380,6 +446,30 @@ TEST_F(HostReservationParserTest, bcastAddress) {
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
}
|
||||
|
||||
// This test verifies that the configuration parser for host reservations
|
||||
// throws an exception when invalid next server address is specified.
|
||||
TEST_F(HostReservationParserTest, malformedNextServer) {
|
||||
std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\","
|
||||
"\"next-server\": \"192.0.2.bogus\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
}
|
||||
|
||||
// This test verifies that the configuration parser for host reservations
|
||||
// throws an exception when zero next server address is specified.
|
||||
TEST_F(HostReservationParserTest, zeroNextServer) {
|
||||
std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\","
|
||||
"\"next-server\": \"0.0.0.0\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
}
|
||||
|
||||
// This test verifies that the configuration parser for host reservations
|
||||
// throws an exception when broadcast next server address is specified.
|
||||
TEST_F(HostReservationParserTest, bcastNextServer) {
|
||||
std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\","
|
||||
"\"next-server\": \"255.255.255.255\" }";
|
||||
testInvalidConfig<HostReservationParser4>(config);
|
||||
}
|
||||
|
||||
// This test verifies that the configuration parser for host reservations
|
||||
// throws an exception when unsupported parameter is specified.
|
||||
TEST_F(HostReservationParserTest, invalidParameterName) {
|
||||
|
@ -192,7 +192,11 @@ TEST_F(HostTest, createFromHWAddrString) {
|
||||
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);
|
||||
@ -205,6 +209,9 @@ TEST_F(HostTest, createFromHWAddrString) {
|
||||
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),
|
||||
@ -264,7 +271,12 @@ TEST_F(HostTest, createFromHWAddrBinary) {
|
||||
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);
|
||||
@ -277,6 +289,9 @@ TEST_F(HostTest, createFromHWAddrBinary) {
|
||||
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
|
||||
@ -644,11 +659,17 @@ TEST_F(HostTest, setValues) {
|
||||
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();
|
||||
@ -664,6 +685,12 @@ TEST_F(HostTest, setValues) {
|
||||
// Broadcast address can't be set.
|
||||
EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_BCAST_ADDRESS()),
|
||||
isc::BadValue);
|
||||
|
||||
// Broadcast and IPv6 are invalid addresses for next server.
|
||||
EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_BCAST_ADDRESS()),
|
||||
isc::BadValue);
|
||||
EXPECT_THROW(host->setNextServer(IOAddress("2001:db8:1::1")),
|
||||
isc::BadValue);
|
||||
}
|
||||
|
||||
// Test that Host constructors initialize client classes from string.
|
||||
@ -918,6 +945,9 @@ TEST_F(HostTest, toText) {
|
||||
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"
|
||||
@ -931,6 +961,9 @@ TEST_F(HostTest, toText) {
|
||||
|
||||
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"
|
||||
@ -945,6 +978,9 @@ TEST_F(HostTest, toText) {
|
||||
"myhost")));
|
||||
|
||||
EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
|
||||
" siaddr=(no)"
|
||||
" sname=(empty)"
|
||||
" file=(empty)"
|
||||
" ipv6_reservations=(none)", host->toText());
|
||||
|
||||
// Add some classes.
|
||||
@ -952,6 +988,9 @@ TEST_F(HostTest, toText) {
|
||||
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());
|
||||
@ -960,6 +999,9 @@ TEST_F(HostTest, 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",
|
||||
|
@ -517,4 +517,10 @@ TEST_F(MySqlHostDataSourceTest, testAddRollback) {
|
||||
EXPECT_FALSE(from_hds);
|
||||
}
|
||||
|
||||
// This test checks that siaddr, sname, file fields can be retrieved
|
||||
/// from a database for a host.
|
||||
TEST_F(MySqlHostDataSourceTest, messageFields) {
|
||||
testMessageFields4();
|
||||
}
|
||||
|
||||
}; // Of anonymous namespace
|
||||
|
@ -475,4 +475,10 @@ TEST_F(PgSqlHostDataSourceTest, testAddRollback) {
|
||||
EXPECT_FALSE(from_hds);
|
||||
}
|
||||
|
||||
// This test checks that siaddr, sname, file fields can be retrieved
|
||||
/// from a database for a host.
|
||||
TEST_F(PgSqlHostDataSourceTest, messageFields) {
|
||||
testMessageFields4();
|
||||
}
|
||||
|
||||
}; // Of anonymous namespace
|
||||
|
@ -469,6 +469,11 @@ ALTER TABLE dhcp6_options
|
||||
ALTER TABLE ipv6_reservations
|
||||
MODIFY reservation_id INT UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
# Add columns holding reservations for siaddr, sname and file fields
|
||||
# carried within DHCPv4 message.
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_next_server INT UNSIGNED NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_server_hostname VARCHAR(64) NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_boot_file_name VARCHAR(128) NULL;
|
||||
|
||||
# Update the schema version number
|
||||
UPDATE schema_version
|
||||
|
@ -471,6 +471,12 @@ CREATE FUNCTION lease6DumpData() RETURNS
|
||||
ORDER BY l.address;
|
||||
$$ LANGUAGE SQL;
|
||||
|
||||
-- Add columns holding reservations for siaddr, sname and file fields
|
||||
-- carried within DHCPv4 message.
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_next_server BIGINT DEFAULT NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_server_hostname VARCHAR(64) DEFAULT NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_boot_file_name VARCHAR(128) DEFAULT NULL;
|
||||
|
||||
-- Set 3.0 schema version.
|
||||
UPDATE schema_version
|
||||
SET version = '3', minor = '0';
|
||||
|
@ -257,6 +257,12 @@ CREATE FUNCTION lease6DumpData() RETURNS
|
||||
ORDER BY l.address;
|
||||
\$\$ LANGUAGE SQL;
|
||||
|
||||
-- Add columns holding reservations for siaddr, sname and file fields
|
||||
-- carried within DHCPv4 message.
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_next_server BIGINT DEFAULT NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_server_hostname VARCHAR(64) DEFAULT NULL;
|
||||
ALTER TABLE hosts ADD COLUMN dhcp4_boot_file_name VARCHAR(128) DEFAULT NULL;
|
||||
|
||||
-- Set 3.0 schema version.
|
||||
UPDATE schema_version
|
||||
SET version = '3', minor = '0';
|
||||
|
Loading…
x
Reference in New Issue
Block a user