diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h index f04ec847fd..03d30338ba 100644 --- a/src/lib/dhcpsrv/host.h +++ b/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 }; diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 28993ea1e3..be07fcbb95 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -14,6 +14,9 @@ #include +#define __STDC_FORMAT_MACROS +#include + #include #include #include @@ -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 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(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(NULL); bind_[0].buffer_type = MYSQL_TYPE_LONG; - bind_[0].buffer = reinterpret_cast(&host_id_); + bind_[0].buffer = reinterpret_cast(&reservation_id_); bind_[0].is_unsigned = MLM_TRUE; // address VARCHAR(39) @@ -697,10 +705,15 @@ public: bind_[4].buffer = reinterpret_cast(&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(&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(&reservation_id_); + bind_[0].is_unsigned = MLM_TRUE; + + // address VARCHAR(39) + bind_[1].buffer_type = MYSQL_TYPE_BLOB; + bind_[1].buffer = reinterpret_cast + (const_cast(&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(&prefix_len_); + bind_[2].is_unsigned = MLM_TRUE; + + // type tinyint + bind_[3].buffer_type = MYSQL_TYPE_TINY; + bind_[3].buffer = reinterpret_cast(&type_); + bind_[3].is_unsigned = MLM_TRUE; + + // dhcp6_iaid INT UNSIGNED + bind_[4].buffer_type = MYSQL_TYPE_LONG; + bind_[4].buffer = reinterpret_cast(&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(&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(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); } } } @@ -926,6 +981,88 @@ MySqlHostDataSource::addQuery(StatementIndex stindex, } } +void +MySqlHostDataSource::getIPv6ReservationCollection(StatementIndex stindex, + MYSQL_BIND* bind, boost::shared_ptr 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 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(host_id); + inbind[0].buffer_type = MYSQL_TYPE_LONG; + inbind[0].buffer = reinterpret_cast(&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 exchange, @@ -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(&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 + (const_cast(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(&tmp); inbind[1].is_unsigned = MLM_TRUE; + ConstHostCollection collection; getHostCollection(GET_HOST_PREFIX, inbind, hostExchange_, collection, true); diff --git a/src/lib/dhcpsrv/mysql_host_data_source.h b/src/lib/dhcpsrv/mysql_host_data_source.h index 5a93d38cbc..393583395d 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.h +++ b/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 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 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 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 aaf3b32f54..cf723fe4f9 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/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 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 ced6d9d7ec..4f89adac4b 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h +++ b/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. /// 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 cc0bc516ef..c9d5d008bb 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/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.