Browse Source

[4212] Patch as provided by Adam Kalmus

 - Tomek verified that it applied cleanly, compiled and
   unit-tests passed.
Tomek Mrugalski 9 years ago
parent
commit
4e9fb31a3d

+ 2 - 0
src/lib/dhcpsrv/host.h

@@ -46,8 +46,10 @@ public:
     /// @brief Type of the reservation.
     ///
     /// Currently supported types are NA and PD.
+    /// Added TA type for IPv6 Reservation implementation.
     enum Type {
         TYPE_NA,
+        TYPE_TA,
         TYPE_PD
     };
 

+ 191 - 44
src/lib/dhcpsrv/mysql_host_data_source.cc

@@ -14,6 +14,9 @@
 
 #include <config.h>
 
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
 #include <asiolink/io_address.h>
 #include <dhcp/duid.h>
 #include <dhcp/hwaddr.h>
@@ -51,14 +54,16 @@ const size_t HOSTNAME_MAX_LEN = 255;
 TaggedStatement tagged_statements[] = {
     {MySqlHostDataSource::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) "
+            "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+            "dhcp4_client_classes, dhcp6_client_classes) "
          "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlHostDataSource::INSERT_V6_RESRV,
-         "INSERT INTO ipv6_reservations(host_id, address, prefix_len, type, dhcp6_iaid) "
-         "VALUES (?,?,?,?,?)"},
+         "INSERT INTO ipv6_reservations(reservation_id, address, prefix_len, type, "
+            "dhcp6_iaid, host_id) "
+         "VALUES (?,?,?,?,?,?)"},
     {MySqlHostDataSource::GET_V6_RESRV,
-         "SELECT address, prefix_len, type, dhcp6_iaid FROM ipv6_reservations "
+         "SELECT reservation_id, address, prefix_len, type, dhcp6_iaid, host_id "
+         "FROM ipv6_reservations "
          "WHERE host_id = ?"},
     {MySqlHostDataSource::GET_HOST_HWADDR_DUID,
             "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
@@ -97,8 +102,8 @@ TaggedStatement tagged_statements[] = {
                 "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
                 "dhcp4_client_classes, dhcp6_client_classes "
             "FROM hosts h, ipv6_reservations r "
-            "WHERE h.host_id = r.host_id AND r.prefix_len = ? "
-            "   AND r.address = ?"},
+            "WHERE h.host_id = r.host_id "
+            "AND r.address = ? AND r.prefix_len = ?"},
     {MySqlHostDataSource::GET_VERSION,
             "SELECT version, minor FROM schema_version"},
     {MySqlHostDataSource::NUM_STATEMENTS, NULL}
@@ -560,7 +565,7 @@ private:
 
 class MySqlIPv6ReservationExchange {
     /// @brief Set number of database columns for this reservation structure
-    static const size_t RESRV_COLUMNS = 5;
+    static const size_t RESRV_COLUMNS = 6;
 
 public:
 
@@ -636,14 +641,15 @@ public:
         return (result);
     }
 
-    /// @brief Create MYSQL_BIND objects for Host Pointer
+    /// @brief Create MYSQL_BIND objects for IPv6 Reservation
     ///
-    /// Fills in the MYSQL_BIND array for sending data in the Host object to
-    /// the database.
+    /// Fills in the MYSQL_BIND array for sending data in the IPv6 Reservation
+    /// object to the database.
     ///
-    /// @param host Host object to be added to the database.
-    ///        None of the fields in the host reservation are modified -
-    ///        the host data is only read.
+    /// @param resv IPv6 reservation object to be added to the database.
+    ///        None of the fields in the reservation are modified -
+    ///        the reservation data is only read.
+    /// @param id ID of a host owning this reservation
     ///
     /// @return Vector of MySQL BIND objects representing the data to be added.
     std::vector<MYSQL_BIND> createBindForSend(const IPv6Resrv& resv, const HostID& id) {
@@ -662,10 +668,12 @@ public:
         // Set up the structures for the various components of the host structure.
 
         try {
-            // host_id : INT UNSIGNED NOT NULL
-            host_id_ = static_cast<uint32_t>(NULL);
+            // reservation_id INT UNSIGNED NOT NULL
+            // The host_id is auto_incremented by MySQL database,
+            // so we need to pass the NULL value
+            reservation_id_ = static_cast<uint32_t>(NULL);
             bind_[0].buffer_type = MYSQL_TYPE_LONG;
-            bind_[0].buffer = reinterpret_cast<char*>(&host_id_);
+            bind_[0].buffer = reinterpret_cast<char*>(&reservation_id_);
             bind_[0].is_unsigned = MLM_TRUE;
 
             // address VARCHAR(39)
@@ -697,10 +705,15 @@ public:
             bind_[4].buffer = reinterpret_cast<char*>(&iaid_);
             bind_[4].is_unsigned = MLM_TRUE;
 
+            // host_id INT UNSIGNED NOT NULL
+            bind_[5].buffer_type = MYSQL_TYPE_LONG;
+            bind_[5].buffer = reinterpret_cast<char*>(&host_id_);
+            bind_[5].is_unsigned = MLM_TRUE;
+
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
-                      "Could not create bind array from Host: "
-                      << host_->getHostname() << ", reason: " << ex.what());
+                      "Could not create bind array from IPv6 Reservation: "
+                      << resv_.toText() << ", reason: " << ex.what());
         }
 
         // Add the data to the vector.  Note the end element is one after the
@@ -723,13 +736,43 @@ public:
         // code that explicitly sets is_null is there, but is commented out.
         memset(bind_, 0, sizeof(bind_));
 
-        /// @todo: set bind_[X] fields here.
+        // reservation_id INT UNSIGNED NOT NULL
+        bind_[0].buffer_type = MYSQL_TYPE_LONG;
+        bind_[0].buffer = reinterpret_cast<char*>(&reservation_id_);
+        bind_[0].is_unsigned = MLM_TRUE;
+
+        // address VARCHAR(39)
+        bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+        bind_[1].buffer = reinterpret_cast<char*>
+                            (const_cast<char*>(&address_[0]));
+        bind_[1].buffer_length = address_len_;
+        bind_[1].length = &address_len_;
+
+        // prefix_len tinyint
+        bind_[2].buffer_type = MYSQL_TYPE_TINY;
+        bind_[2].buffer = reinterpret_cast<char*>(&prefix_len_);
+        bind_[2].is_unsigned = MLM_TRUE;
+
+        // type tinyint
+        bind_[3].buffer_type = MYSQL_TYPE_TINY;
+        bind_[3].buffer = reinterpret_cast<char*>(&type_);
+        bind_[3].is_unsigned = MLM_TRUE;
+
+        // dhcp6_iaid INT UNSIGNED
+        bind_[4].buffer_type = MYSQL_TYPE_LONG;
+        bind_[4].buffer = reinterpret_cast<char*>(&iaid_);
+        bind_[4].is_unsigned = MLM_TRUE;
+
+        // host_id INT UNSIGNED NOT NULL
+        bind_[5].buffer_type = MYSQL_TYPE_LONG;
+        bind_[5].buffer = reinterpret_cast<char*>(&host_id_);
+        bind_[5].is_unsigned = MLM_TRUE;
 
         // Add the error flags
         setErrorIndicators(bind_, error_, RESRV_COLUMNS);
 
         // .. and check that we have the numbers correct at compile time.
-        BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS);
+        BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
 
         // Add the data to the vector.  Note the end element is one after the
         // end of the array.
@@ -745,9 +788,31 @@ public:
     ///
     /// @return IPv6Resrv object (containing IPv6 address or prefix reservation)
     IPv6Resrv getIPv6ReservData(){
-        /// @todo: Implement actual extraction.
-        IPv6Resrv r(IPv6Resrv::TYPE_NA, IOAddress("::"), 128);
 
+        // Set the IPv6 Reservation type (0 = IA_NA, 1 = IA_TA, 2 = IA_PD)
+        IPv6Resrv::Type type = IPv6Resrv::TYPE_NA;
+
+        switch (type_) {
+        case 0:
+            type = IPv6Resrv::TYPE_NA;
+            break;
+
+        case 1:
+            type = IPv6Resrv::TYPE_TA;
+            break;
+
+        case 2:
+            type = IPv6Resrv::TYPE_PD;
+            break;
+
+        default:
+            isc_throw(BadValue,
+                    "invalid IPv6 reservation type returned: "
+                    << static_cast<int>(type_)
+                    << ". Only 0, 1 or 2 are allowed.");
+        }
+
+        IPv6Resrv r(type, IOAddress(address_), prefix_len_);
         return (r);
     }
 
@@ -787,6 +852,7 @@ public:
 
 private:
     uint64_t	host_id_;        /// Host unique identifier
+    uint64_t    reservation_id_; /// Host unique identifier
     size_t      host_id_length_; /// Length of the host unique ID
     std::string address_;        ///< Address (or prefix)
     size_t      address_len_;    ///< Length of the textual address representation
@@ -805,9 +871,9 @@ private:
     IPv6Resrv   resv_;
 
     MYSQL_BIND  bind_[RESRV_COLUMNS];
-    std::string columns_[RESRV_COLUMNS];	/// Column names
+    std::string columns_[RESRV_COLUMNS]; /// Column names
     my_bool     error_[RESRV_COLUMNS];   /// Error array
-    HostPtr     host_;			// Pointer to Host object
+    HostPtr     host_;			 /// Pointer to Host object
 };
 
 // MySqlHostDataSource Constructor and Destructor
@@ -879,21 +945,10 @@ MySqlHostDataSource::add(const HostPtr& host) {
             return;
         }
 
-        // Ok, there are v6 reservations. Let's insert them. But first, we need
-        // to learn what's the host_id of the host we just added.
-
-        /// @todo: See how get6() is done in hostMgr - calls with duid only first,
-        /// and if can't find it, then calls with hwaddr only.
-        ConstHostPtr from_db = get6(host->getIPv6SubnetID(), host->getDuid(),
-                                    host->getHWAddress());
-        if (!from_db) {
-            // Oops, we have a problem. We can't find the host we just added.
-            isc_throw(DbOperationError, "Unable to retrieve the host that just "
-                      "had been added");
-        }
-
+        // Gets the last inserted hosts id
+        uint64_t host_id = mysql_insert_id(conn_.mysql_);
         for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second; ++resv) {
-            addResv(resv->second, from_db->getHostId());
+            addResv(resv->second, host_id);
         }
     }
 }
@@ -927,6 +982,88 @@ MySqlHostDataSource::addQuery(StatementIndex stindex,
 }
 
 void
+MySqlHostDataSource::getIPv6ReservationCollection(StatementIndex stindex,
+        MYSQL_BIND* bind, boost::shared_ptr<MySqlIPv6ReservationExchange> exchange,
+        IPv6ResrvCollection& result) const {
+
+    // Bind the selection parameters to the statement
+    int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
+    checkError(status, stindex, "unable to bind WHERE clause parameter");
+
+    // Set up the MYSQL_BIND array for the data being returned and bind it to
+    // the statement.
+    std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
+    status = mysql_stmt_bind_result(conn_.statements_[stindex], &outbind[0]);
+    checkError(status, stindex, "unable to bind SELECT clause parameters");
+
+    // Execute the statement
+    status = mysql_stmt_execute(conn_.statements_[stindex]);
+    checkError(status, stindex, "unable to execute");
+
+    // Ensure that all the lease information is retrieved in one go to avoid
+    // overhead of going back and forth between client and server.
+    status = mysql_stmt_store_result(conn_.statements_[stindex]);
+    checkError(status, stindex, "unable to set up for storing all results");
+
+    // Set up the fetch "release" object to release resources associated
+    // with the call to mysql_stmt_fetch when this method exits, then
+    // retrieve the data.
+    MySqlFreeResult fetch_release(conn_.statements_[stindex]);
+    while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
+        try {
+            result.insert(IPv6ResrvTuple(exchange->getIPv6ReservData().getType(),
+                                            exchange->getIPv6ReservData()));
+
+        } catch (const isc::BadValue& ex) {
+            // Rethrow the exception with a bit more data.
+            isc_throw(BadValue, ex.what() << ". Statement is <" <<
+                    conn_.text_statements_[stindex] << ">");
+        }
+    }
+
+    // How did the fetch end?
+    if (status == 1) {
+        // Error - unable to fetch results
+        checkError(status, stindex, "unable to fetch results");
+    } else if (status == MYSQL_DATA_TRUNCATED) {
+        // Data truncated - throw an exception indicating what was at fault
+        isc_throw(DataTruncated, conn_.text_statements_[stindex]
+                  << " returned truncated data: columns affected are "
+                  << exchange->getErrorColumns());
+    }
+}
+
+IPv6ResrvCollection
+MySqlHostDataSource::getAllReservations(HostID host_id) const{
+
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[1];
+    memset(inbind, 0, sizeof(inbind));
+
+    uint32_t id = static_cast<uint32_t>(host_id);
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&id);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    IPv6ResrvCollection result;
+    getIPv6ReservationCollection(GET_V6_RESRV, inbind, resvExchange_, result);
+
+    return (result);
+}
+
+void
+MySqlHostDataSource::assignReservations(HostPtr& host) const {
+
+    IPv6ResrvCollection reservations;
+    reservations = getAllReservations(host->getHostId());
+
+    for (IPv6ResrvIterator resv = reservations.begin(); resv != reservations.end(); ++resv){
+        host->addReservation(resv->second);
+
+    }
+}
+
+void
 MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
         boost::shared_ptr<MySqlHostReservationExchange> exchange,
         ConstHostCollection& result, bool single) const {
@@ -955,9 +1092,12 @@ MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
     // retrieve the data.
     MySqlFreeResult fetch_release(conn_.statements_[stindex]);
     int count = 0;
+    HostPtr host;
     while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
         try {
-            result.push_back(exchange->getHostData());
+            host = exchange->getHostData();
+            assignReservations(host);
+            result.push_back(host);
 
         } catch (const isc::BadValue& ex) {
             // Rethrow the exception with a bit more data.
@@ -1228,15 +1368,22 @@ MySqlHostDataSource::get6(const asiolink::IOAddress& prefix,
     MYSQL_BIND inbind[2];
     memset(inbind, 0, sizeof(inbind));
 
-    inbind[0].buffer_type = MYSQL_TYPE_LONG;
-    inbind[0].buffer = reinterpret_cast<char*>(&prefix.toBytes()[0]);
-    inbind[0].is_unsigned = MLM_TRUE;
+    std::string addr6 = prefix.toText();
+    unsigned long addr6_length = addr6.size();
+
+    inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+    inbind[0].buffer = reinterpret_cast<char*>
+                        (const_cast<char*>(addr6.c_str()));
+    inbind[0].length = &addr6_length;
+    inbind[0].buffer_length = addr6_length;
+
 
     uint8_t tmp = prefix_len;
-    inbind[1].buffer_type = MYSQL_TYPE_LONG;
+    inbind[1].buffer_type = MYSQL_TYPE_TINY;
     inbind[1].buffer = reinterpret_cast<char*>(&tmp);
     inbind[1].is_unsigned = MLM_TRUE;
 
+
     ConstHostCollection collection;
     getHostCollection(GET_HOST_PREFIX, inbind, hostExchange_,
                       collection, true);

+ 36 - 1
src/lib/dhcpsrv/mysql_host_data_source.h

@@ -165,6 +165,21 @@ public:
     virtual ConstHostPtr
     get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
 
+    /// @brief Returns all IPv6 reservations assigned to single host
+    ///
+    /// @param host_id ID of a host owning IPv6 reservations
+    ///
+    /// @return Collection of IPv6 reservations
+    virtual IPv6ResrvCollection
+    getAllReservations(HostID host_id) const;
+
+    /// @brief Retrieves all IPv6 reservations for a single host and then
+    ///         adds them to that host.
+    ///
+    /// @param host Pointer to a host to be populated with IPv6 reservations.
+    void
+    assignReservations(HostPtr& host) const;
+
     /// @brief Adds a new host to the collection.
     ///
     /// The implementations of this method should guard against duplicate
@@ -279,6 +294,25 @@ private:
             boost::shared_ptr<MySqlHostReservationExchange> exchange,
             ConstHostCollection& result, bool single = false) const;
 
+    /// @brief Get IPv6 Reservation Collection
+    ///
+    /// This method obtains multiple IPv6 reservations from the database.
+    ///
+    /// @param stindex Index of statement being executed
+    /// @param bind MYSQL_BIND array for input parameters
+    /// @param exchange Exchange object to use
+    /// @param result IPv6ResrvCollection object returned.  Note that any
+    ///        reservations in the collection when this method is called
+    ///        are not erased: the new data is appended to the end.
+    ///
+    /// @throw isc::dhcp::BadValue Data retrieved from the database was invalid.
+    /// @throw isc::dhcp::DbOperationError An operation on the open database has
+    ///        failed.
+    void getIPv6ReservationCollection(StatementIndex stindex, MYSQL_BIND* bind,
+            boost::shared_ptr<MySqlIPv6ReservationExchange> exchange,
+            IPv6ResrvCollection& result) const;
+
+
     /// @brief Check Error and Throw Exception
     ///
     /// Virtually all MySQL functions return a status which, if non-zero,
@@ -308,7 +342,8 @@ private:
 
     /// @brief Adds IPv6 Reservation
     ///
-    /// @todo: describe parameters here
+    /// @param resv IPv6 Reservation to be added
+    /// @param id ID of a host owning this reservation
     void addResv(const IPv6Resrv& resv, HostID id);
     
     // Members

+ 63 - 8
src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc

@@ -299,8 +299,11 @@ GenericHostDataSourceTest::compareReservations6(IPv6ResrvRange resrv1,
 
     if (std::distance(resrv1.first, resrv1.second) > 0) {
         if (expect_match){
-            /// @todo Compare every reservation from both hosts
-            ///       This is part of the work for #4212.
+            for (; resrv1.first != resrv1.second; resrv1.first++, resrv2.first++){
+                EXPECT_EQ(resrv1.first->second.getType(), resrv2.first->second.getType());
+                EXPECT_EQ(resrv1.first->second.getPrefixLen(), resrv2.first->second.getPrefixLen());
+                EXPECT_EQ(resrv1.first->second.getPrefix(), resrv2.first->second.getPrefix());
+            }
         }
     }
 }
@@ -608,8 +611,8 @@ void GenericHostDataSourceTest::testGet6ByHWAddr() {
     ASSERT_TRUE(hdsptr_);
 
     // Create a host reservations.
-    HostPtr host1 = initializeHost6("2001:db8::0", BaseHostDataSource::ID_HWADDR, true);
-    HostPtr host2 = initializeHost6("2001:db8::1", BaseHostDataSource::ID_HWADDR, true);
+    HostPtr host1 = initializeHost6("2001:db8::1", BaseHostDataSource::ID_HWADDR, true);
+    HostPtr host2 = initializeHost6("2001:db8::2", BaseHostDataSource::ID_HWADDR, true);
 
     // Sanity check: make sure the hosts have different HW addresses.
     ASSERT_TRUE(host1->getHWAddress());
@@ -639,8 +642,8 @@ void GenericHostDataSourceTest::testGet6ByClientId() {
     ASSERT_TRUE(hdsptr_);
 
     // Create a host reservations.
-    HostPtr host1 = initializeHost6("2001:db8::0", BaseHostDataSource::ID_DUID, true);
-    HostPtr host2 = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID, true);
+    HostPtr host1 = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID, true);
+    HostPtr host2 = initializeHost6("2001:db8::2", BaseHostDataSource::ID_DUID, true);
 
     // Sanity check: make sure the hosts have different HW addresses.
     ASSERT_TRUE(host1->getDuid());
@@ -754,8 +757,7 @@ void GenericHostDataSourceTest::testAddDuplicate() {
     ASSERT_TRUE(hdsptr_);
 
     // Create a host reservations.
-    HostPtr host = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID,
-                                   true);
+    HostPtr host = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID, true);
 
     // Add this reservation once.
     ASSERT_NO_THROW(hdsptr_->add(host));
@@ -765,6 +767,59 @@ void GenericHostDataSourceTest::testAddDuplicate() {
 
 }
 
+void GenericHostDataSourceTest::testAddr6AndPrefix(){
+    // Make sure we have the pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+
+    // Create a host reservations with prefix reservation (prefix = true)
+    HostPtr host = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID, true);
+
+    // Create IPv6 reservation (for an address) and add it to the host
+    IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2"), 128);
+    host->addReservation(resv);
+
+    // Add this reservation
+    ASSERT_NO_THROW(hdsptr_->add(host));
+
+    // Get this host by DUID
+    ConstHostPtr from_hds = hdsptr_->get6(host->getIPv6SubnetID(), host->getDuid(), HWAddrPtr());
+
+    // Make sure we got something back
+    ASSERT_TRUE(from_hds);
+
+    // Check if reservations are the same
+    compareReservations6(host->getIPv6Reservations(), from_hds->getIPv6Reservations(), true);
+}
+
+void GenericHostDataSourceTest::testMultipletReservations(){
+    // Make sure we have the pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+    uint8_t len = 128;
+
+    HostPtr host = initializeHost6("2001:db8::1", BaseHostDataSource::ID_DUID, false);
+
+    // Add some reservations
+    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len);
+    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len);
+    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len);
+
+    host->addReservation(resv1);
+    host->addReservation(resv2);
+    host->addReservation(resv3);
+
+    ASSERT_NO_THROW(hdsptr_->add(host));
+
+
+    ConstHostPtr from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), len);
+
+    // Make sure we got something back
+    ASSERT_TRUE(from_hds);
+
+    // Check if hosts are the same
+    compareHosts(host, from_hds);
+
+}
+
 }; // namespace test
 }; // namespace dhcp
 }; // namespace isc

+ 9 - 0
src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h

@@ -206,6 +206,15 @@ public:
     /// Uses gtest macros to report failures.
     void testGet6ByClientId();
 
+    /// @brief Test verifies if a host reservation can be stored with both
+    ///         IPv6 address and prefix.
+    /// Uses gtest macros to report failures.
+    void testAddr6AndPrefix();
+
+    /// @brief Tests if host with multiple IPv6 reservations can be added and then
+    ///         retrieved correctly.
+    void testMultipletReservations();
+
     /// @brief Test if host reservations made for different IPv6 subnets
     ///        are handled correctly.
     ///

+ 6 - 10
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc

@@ -280,53 +280,49 @@ TEST_F(MySqlHostDataSourceTest, DISABLED_hwaddrOrClientId2) {
 // Test verifies that host with IPv6 address and DUID can be added and
 // later retrieved by IPv6 address.
 TEST_F(MySqlHostDataSourceTest, get6AddrWithDuid) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGetByIPv6(BaseHostDataSource::ID_DUID, false);
 }
 
 // Test verifies that host with IPv6 address and HWAddr can be added and
 // later retrieved by IPv6 address.
 TEST_F(MySqlHostDataSourceTest, get6AddrWithHWAddr) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGetByIPv6(BaseHostDataSource::ID_HWADDR, false);
 }
 
 // Test verifies that host with IPv6 prefix and DUID can be added and
 // later retrieved by IPv6 prefix.
 TEST_F(MySqlHostDataSourceTest, get6PrefixWithDuid) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGetByIPv6(BaseHostDataSource::ID_DUID, true);
 }
 
 // Test verifies that host with IPv6 prefix and HWAddr can be added and
 // later retrieved by IPv6 prefix.
 TEST_F(MySqlHostDataSourceTest, get6PrefixWithHWaddr) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGetByIPv6(BaseHostDataSource::ID_HWADDR, true);
 }
 
 // Test verifies if a host reservation can be added and later retrieved by
 // hardware address.
 TEST_F(MySqlHostDataSourceTest, get6ByHWaddr) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGet6ByHWAddr();
 }
 
 // Test verifies if a host reservation can be added and later retrieved by
 // client identifier.
 TEST_F(MySqlHostDataSourceTest, get6ByClientId) {
-    /// @todo: Uncomment when IPv6 support (4212) is implemented.
     testGet6ByClientId();
 }
 
 // Test verifies if a host reservation can be stored with both IPv6 address and
 // prefix.
 TEST_F(MySqlHostDataSourceTest, addr6AndPrefix) {
-    /// @todo: Implement this test as part of #4212.
+    testAddr6AndPrefix();
+}
 
-    /// @todo: Add host reservation with an IPv6 address and IPv6 prefix,
-    /// retrieve it and verify that both v6 address and prefix are retrieved
-    /// correctly.
+// Tests if host with multiple IPv6 reservations can be added and then
+// retrieved correctly. Test checks reservations comparing.
+TEST_F(MySqlHostDataSourceTest, multipleReservations){
+    testMultipletReservations();
 }
 
 // Test verifies if multiple client classes for IPv4 can be stored.