Browse Source

[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.
Marcin Siodelski 8 years ago
parent
commit
8a23588bfe

+ 54 - 3
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<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: "
@@ -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,

+ 64 - 0
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

+ 7 - 0
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

+ 6 - 0
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

+ 6 - 0
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