From: Stephen Morris Date: Wed, 21 Nov 2012 19:38:26 +0000 (+0000) Subject: [2404] Add getLease4(const IOAddress&, SubnetId) X-Git-Tag: bind10-1.0.0-beta-release~39^2~17 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=af71689ee49cd8668dd830e7a90f06c9b7fc7de7;p=thirdparty%2Fkea.git [2404] Add getLease4(const IOAddress&, SubnetId) Add ability to select IPv4 leases by address and Subnet ID. --- diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index aa057c15dd..c07fad42e8 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -110,8 +110,6 @@ TaggedStatement tagged_statements[] = { namespace isc { namespace dhcp { - - /// @brief Exchange MySQL and Lease4 Data /// /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to @@ -306,9 +304,9 @@ private: MYSQL_TIME expire_; ///< Lease expiry time const my_bool false_; ///< "false" for MySql Lease4Ptr lease_; ///< Pointer to lease object - uint32_t valid_lifetime_; ///< Lease time uint32_t subnet_id_; ///< Subnet identification const my_bool true_; ///< "true_" for MySql + uint32_t valid_lifetime_; ///< Lease time }; @@ -598,12 +596,12 @@ private: const my_bool false_; ///< "false" for MySql uint32_t iaid_; ///< Identity association ID Lease6Ptr lease_; ///< Pointer to lease object - uint32_t valid_lifetime_; ///< Lease time uint8_t lease_type_; ///< Lease type uint8_t prefixlen_; ///< Prefix length uint32_t pref_lifetime_; ///< Preferred lifetime uint32_t subnet_id_; ///< Subnet identification const my_bool true_; ///< "true_" for MySql + uint32_t valid_lifetime_; ///< Lease time }; @@ -611,7 +609,7 @@ private: /// /// When a MySQL statement is exected, to fetch the results the function /// mysql_stmt_fetch() must be called. As well as getting data, this -/// allocated internal state. Subsequent calls to mysql_stmt_fetch +/// allocates internal state. Subsequent calls to mysql_stmt_fetch /// can be made, but when all the data is retrieved, mysql_stmt_free_result /// must be called to free up the resources allocated. /// @@ -648,7 +646,7 @@ private: }; -// MySqlLeaseMgr Methods +// MySqlLeaseMgr Constructor and Destructor MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters) : LeaseMgr(parameters), mysql_(NULL) { @@ -751,6 +749,9 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire, } + +// Database acess method + void MySqlLeaseMgr::openDatabase() { @@ -812,7 +813,7 @@ MySqlLeaseMgr::openDatabase() { // changed and so the "affected rows" (retrievable from MySQL) is zero. // This makes it hard to distinguish whether the UPDATE changed no rows // because no row matching the WHERE clause was found, or because a - // row was found by no data was altered. + // row was found but no data was altered. MYSQL* status = mysql_real_connect(mysql_, host, user, password, name, 0, NULL, CLIENT_FOUND_ROWS); if (status != mysql_) { @@ -820,6 +821,12 @@ MySqlLeaseMgr::openDatabase() { } } +// Prepared statement setup. The textual form of the SQL statement is stored +// in a vector of strings (text_statements_) and is used in the output of +// error messages. The SQL statement is also compiled into a "prepared +// statement" (stored in statements_), which avoids the overhead of compilation +// during use. As these allocate resources, the class destructor explicitly +// destroys the prepared statements. void MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) { @@ -865,7 +872,7 @@ MySqlLeaseMgr::prepareStatements() { } -// Common add lease code +// Add leases to the database bool MySqlLeaseMgr::addLease(StatementIndex stindex, std::vector& bind) { @@ -909,6 +916,36 @@ MySqlLeaseMgr::addLease(const Lease6Ptr& lease) { return (addLease(INSERT_LEASE6, bind)); } +// A convenience function used in the various getLease() methods. It binds +// the selection parameters to the prepared statement, and binds the variables +// that will receive the data. These are stored in the MySqlLease6Exchange +// object associated with the lease manager and converted to a Lease6 object +// when retrieved. +template +void +MySqlLeaseMgr::bindAndExecute(StatementIndex stindex, Exchange& exchange, + MYSQL_BIND* inbind) const { + + // Bind the input parameters to the statement + int status = mysql_stmt_bind_param(statements_[stindex], inbind); + checkError(status, stindex, "unable to bind WHERE clause parameter"); + + // Set up the SELECT clause + std::vector outbind = exchange->createBindForReceive(); + + // Bind the output parameters to the statement + status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]); + checkError(status, stindex, "unable to bind SELECT caluse parameters"); + + // Execute the statement + status = mysql_stmt_execute(statements_[stindex]); + checkError(status, stindex, "unable to execute"); +} + +// Extraction of leases from the database. Much the code has common logic +// with the difference between V4 and V6 being the data types of the +// objects involved. For this reason, the common logic is inside a +// template method. template void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* inbind, @@ -918,7 +955,7 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* inbind, // to fields in the exchange object, then execute the prepared statement. bindAndExecute(stindex, exchange, inbind); - // Fetch the data and set up the "release" object to release associated + // Fetch the data and set up the "free result" object to release associated // resources when this method exits. MySqlFreeResult fetch_release(statements_[stindex]); int status = mysql_stmt_fetch(statements_[stindex]); @@ -967,11 +1004,20 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { Lease4Ptr -MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */, - SubnetID /* subnet_id */) const { - isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&, SubnetID) " - "not implemented yet"); - return (Lease4Ptr()); +MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr, + SubnetID subnet_id) const { + + // As the address is the unique primary key of the lease4 table, there can + // only be one lease with a given address. Therefore we will get that + // lease and do the filtering on subnet ID here. + Lease4Ptr result = getLease4(addr); + if (result && (result->subnet_id_ != subnet_id)) { + + // Lease found but IDs do not match. Return null pointer + result.reset(); + } + + return (result); } @@ -1009,31 +1055,6 @@ MySqlLeaseMgr::getLease4(const ClientId& /* clientid */, } -// A convenience function used in the various getLease() methods. It binds -// the selection parameters to the prepared statement, and binds the variables -// that will receive the data. These are stored in the MySqlLease6Exchange -// object associated with the lease manager and converted to a Lease6 object -// when retrieved. -template -void -MySqlLeaseMgr::bindAndExecute(StatementIndex stindex, Exchange& exchange, - MYSQL_BIND* inbind) const { - - // Bind the input parameters to the statement - int status = mysql_stmt_bind_param(statements_[stindex], inbind); - checkError(status, stindex, "unable to bind WHERE clause parameter"); - - // Set up the SELECT clause - std::vector outbind = exchange->createBindForReceive(); - - // Bind the output parameters to the statement - status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]); - checkError(status, stindex, "unable to bind SELECT caluse parameters"); - - // Execute the statement - status = mysql_stmt_execute(statements_[stindex]); - checkError(status, stindex, "unable to execute"); -} Lease6Ptr diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index 7db8d06d82..c55bd4b9e3 100644 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -477,13 +477,13 @@ public: // Check they were created for (int i = 0; i < leases.size(); ++i) { - EXPECT_TRUE(leases[i]); + ASSERT_TRUE(leases[i]); } // Check they are different for (int i = 0; i < (leases.size() - 1); ++i) { for (int j = (i + 1); j < leases.size(); ++j) { - EXPECT_TRUE(leases[i] != leases[j]); + ASSERT_TRUE(leases[i] != leases[j]); } } } @@ -731,15 +731,15 @@ TEST_F(MySqlLeaseMgrTest, basicLease4) { reopen(); Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); l_returned = lmptr_->getLease4(ioaddress4_[2]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[2], l_returned); l_returned = lmptr_->getLease4(ioaddress4_[3]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[3], l_returned); // Check that we can't add a second lease with the same address @@ -754,7 +754,7 @@ TEST_F(MySqlLeaseMgrTest, basicLease4) { // Check that the second address is still there. l_returned = lmptr_->getLease4(ioaddress4_[2]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[2], l_returned); } @@ -782,15 +782,15 @@ TEST_F(MySqlLeaseMgrTest, basicLease6) { reopen(); Lease6Ptr l_returned = lmptr_->getLease6(ioaddress6_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); l_returned = lmptr_->getLease6(ioaddress6_[2]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[2], l_returned); l_returned = lmptr_->getLease6(ioaddress6_[3]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[3], l_returned); // Check that we can't add a second lease with the same address @@ -805,18 +805,84 @@ TEST_F(MySqlLeaseMgrTest, basicLease6) { // Check that the second address is still there. l_returned = lmptr_->getLease6(ioaddress6_[2]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[2], l_returned); } +// @brief Check GetLease4 methods - Access by Address and SubnetID +// +// Adds leases to the database and checks that they can be accessed via +// a combination of Address, SubnetID +TEST_F(MySqlLeaseMgrTest, getLease4AddressSubnetId) { + // Get the leases to be used for the test. + vector leases = createLeases4(); + + // Add just one to the database. + EXPECT_TRUE(lmptr_->addLease(leases[1])); + + // Look for a known lease with a valid Subnet ID + Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1], 73); + ASSERT_TRUE(l_returned); + detailCompareLease(leases[1], l_returned); + + // Look for a lease known to be in the database with an invalid Subnet ID + l_returned = lmptr_->getLease4(ioaddress4_[1], 74); + EXPECT_FALSE(l_returned); + + // Look for a lease known not to be in the database with a valid Subnet ID + l_returned = lmptr_->getLease4(ioaddress4_[2], 73); + EXPECT_FALSE(l_returned); + + // Look for a lease known not to be in the database with and invalid + l_returned = lmptr_->getLease4(ioaddress4_[2], 74); + EXPECT_FALSE(l_returned); +} + +// @brief Check GetLease4 methods - Access by Hardware Address +// +// Adds leases to the database and checks that they can be accessed via +// hardware address +TEST_F(MySqlLeaseMgrTest, getLease4AddressHwaddr) { + FAIL() << "Test not complete"; +/* + // Get the leases to be used for the test and add to the database. + vector leases = createLeases4(); + for (int i = 0; i < leases.size(); ++i) { + EXPECT_TRUE(lmptr_->addLease(leases[i])); + } + + // Get a known hardware address + vector hwaddr = leases[1]->hwaddr_; + EXPECT_FALSE(hwaddr.empty()); + + // Look for a lease with a valid hardware address + Lease4Ptr l_returned = lmptr_->getLease4(hwaddr); + ASSERT_TRUE(l_returned); + detailCompareLease(leases[1], l_returned); + + // Look for a lease with an invalid valid hardware address + hwaddr[0] += 1; + Lease4Ptr l_returned = lmptr_->getLease4(hwaddr); + EXPECT_FALSE(l_returned); + + // Check it handles an empty hardware address + hwaddr.clear(); + Lease4Ptr l_returned = lmptr_->getLease4(hwaddr); + EXPECT_FALSE(l_returned); + + // Add a lease with an empty hardware address to the database and + // check that it find that. +*/ +} + // @brief Check GetLease6 methods - Access by DUID/IAID // // Adds leases to the database and checks that they can be accessed via // a combination of DIUID and IAID. -TEST_F(MySqlLeaseMgrTest, getLease6Extended1) { +TEST_F(MySqlLeaseMgrTest, getLease6DuidIaid) { // Get the leases to be used for the test. vector leases = createLeases6(); - EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5 + ASSERT_LE(6, leases.size()); // Expect to access leases 0 through 5 // Add them to the database for (int i = 0; i < leases.size(); ++i) { @@ -860,10 +926,10 @@ TEST_F(MySqlLeaseMgrTest, getLease6Extended1) { // // Adds leases to the database and checks that they can be accessed via // a combination of DIUID and IAID. -TEST_F(MySqlLeaseMgrTest, getLease6Extended2) { +TEST_F(MySqlLeaseMgrTest, getLease6DuidIaidSubnetId) { // Get the leases to be used for the test. vector leases = createLeases6(); - EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5 + ASSERT_LE(6, leases.size()); // Expect to access leases 0 through 5 // Add them to the database for (int i = 0; i < leases.size(); ++i) { @@ -904,7 +970,7 @@ TEST_F(MySqlLeaseMgrTest, getLease6Extended2) { TEST_F(MySqlLeaseMgrTest, updateLease6) { // Get the leases to be used for the test. vector leases = createLeases6(); - EXPECT_LE(3, leases.size()); // Expect to access leases 0 through 5 + ASSERT_LE(3, leases.size()); // Expect to access leases 0 through 2 // Add a lease to the database and check that the lease is there. EXPECT_TRUE(lmptr_->addLease(leases[1])); @@ -912,7 +978,7 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) { reopen(); Lease6Ptr l_returned = lmptr_->getLease6(ioaddress6_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); // Modify some fields in lease 1 (not the address) and update it. @@ -926,7 +992,7 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) { // ... and check what is returned is what is expected. l_returned.reset(); l_returned = lmptr_->getLease6(ioaddress6_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); // Alter the lease again and check. @@ -938,14 +1004,14 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) { l_returned.reset(); l_returned = lmptr_->getLease6(ioaddress6_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); // Check we can do an update without changing data. lmptr_->updateLease6(leases[1]); l_returned.reset(); l_returned = lmptr_->getLease6(ioaddress6_[1]); - EXPECT_TRUE(l_returned); + ASSERT_TRUE(l_returned); detailCompareLease(leases[1], l_returned); // Try updating a lease not in the database.