From: Marcin Siodelski Date: Tue, 23 Aug 2016 15:43:50 +0000 (+0200) Subject: [4552] MySQL backend now supports storing siaddr, sname and file. X-Git-Tag: trac4631_base~4^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a23588bfe82a937241d75d6df7adc1335d59ff8;p=thirdparty%2Fkea.git [4552] MySQL backend now supports storing siaddr, sname and file. In addition, added a generic unit test for MySQL and Postgres, which tests inertion and retrieval of these values. --- diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index ba1da3b504..7421facd5a 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -120,6 +120,8 @@ public: 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 @@ -320,6 +322,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(host->getNextServer()); + bind_[9].buffer_type = MYSQL_TYPE_LONG; + bind_[9].buffer = reinterpret_cast(&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: " @@ -506,10 +534,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); @@ -1850,8 +1900,9 @@ TaggedStatement 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, diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index 4e50b3f8bf..009985e70c 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -240,6 +240,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(), @@ -1309,6 +1312,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 diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h index b0ed22c2a7..79b9f97b33 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h @@ -496,6 +496,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 diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index 1ef01548c1..d5f9a846f8 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -503,4 +503,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 diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 8d58637c5f..8f22257ddb 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -464,4 +464,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