diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.cc b/src/hooks/dhcp/lease_cmds/lease_cmds.cc index ee7f7c66e3..14d1f3ab4a 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.cc @@ -107,8 +107,8 @@ public: /// @brief Default constructor. Parameters() - :addr("::"), query_type(TYPE_ADDR), lease_type(Lease::TYPE_NA), - iaid(0) { + : addr("::"), query_type(TYPE_ADDR), lease_type(Lease::TYPE_NA), + iaid(0) { } }; @@ -303,11 +303,12 @@ public: /// /// @param parameters parameters extracted from the command. /// - /// @return Address of the lease to be deleted. + /// @return Lease of the lease to be deleted. + /// /// @throw InvalidParameter if the DUID is not found when needed to /// find the lease or if the query type is by HW address. /// @throw InvalidOperation if the query type is unknown. - IOAddress getIPv6AddressForDelete(const Parameters& parameters) const; + Lease6Ptr getIPv6LeaseForDelete(const Parameters& parameters) const; /// @brief Returns a map holding brief information about a lease which /// failed to be deleted, updated or added. @@ -1018,19 +1019,21 @@ int LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) { Parameters p; Lease4Ptr lease4; - IOAddress addr(IOAddress::IPV4_ZERO_ADDRESS()); try { extractCommand(handle); p = getParameters(false, cmd_args_); switch (p.query_type) { case Parameters::TYPE_ADDR: { - // If address was specified explicitly, let's use it as is. - addr = p.addr; + lease4 = LeaseMgrFactory::instance().getLease4(p.addr); + if (!lease4) { + setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY); + return (0); + } break; } - case Parameters::TYPE_HWADDR: + case Parameters::TYPE_HWADDR: { if (!p.hwaddr) { isc_throw(InvalidParameter, "Program error: Query by hw-address " "requires hwaddr to be specified"); @@ -1042,12 +1045,9 @@ LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) { setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY); return (0); } - - // Found it, can use it as is. - addr = lease4->addr_; break; - - case Parameters::TYPE_CLIENT_ID: + } + case Parameters::TYPE_CLIENT_ID: { if (!p.client_id) { isc_throw(InvalidParameter, "Program error: Query by client-id " "requires client-id to be specified"); @@ -1059,25 +1059,19 @@ LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) { setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY); return (0); } - - // Found it, can use it as is. - addr = lease4->addr_; break; - - case Parameters::TYPE_DUID: + } + case Parameters::TYPE_DUID: { isc_throw(InvalidParameter, "Delete by duid is not allowed in v4."); break; - + } default: { isc_throw(InvalidOperation, "Unknown query type: " << static_cast(p.query_type)); break; } } - Lease4Ptr lease(new Lease4()); - lease->addr_ = addr; - - if (LeaseMgrFactory::instance().deleteLease(lease)) { + if (LeaseMgrFactory::instance().deleteLease(lease4)) { setSuccessResponse(handle, "IPv4 lease deleted."); } else { setErrorResponse (handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY); @@ -1122,7 +1116,7 @@ LeaseCmdsImpl::lease6BulkApplyHandler(CalloutHandle& handle) { // Parse deleted leases without deleting them from the database // yet. If any of the deleted leases or new leases appears to be // malformed we can easily rollback. - std::list > parsed_deleted_list; + std::list > parsed_deleted_list; if (deleted_leases) { auto leases_list = deleted_leases->listValue(); @@ -1130,9 +1124,9 @@ LeaseCmdsImpl::lease6BulkApplyHandler(CalloutHandle& handle) { for (auto lease_params : leases_list) { // Parsing the lease may throw and it means that the lease // information is malformed. - Parameters p = getParameters(true, lease_params); - auto lease_addr = getIPv6AddressForDelete(p); - parsed_deleted_list.push_back(std::make_pair(p, lease_addr)); + Parameters p = getParameters(true, lease_params); + auto lease = getIPv6AddressForDelete(p); + parsed_deleted_list.push_back(std::make_pair(p, lease)); } } @@ -1167,17 +1161,14 @@ LeaseCmdsImpl::lease6BulkApplyHandler(CalloutHandle& handle) { // This part is outside of the try-catch because an exception // indicates that the command is malformed. - Parameters p = lease_params_pair.first; - auto lease_addr = lease_params_pair.second; + Parameters p = lease_params_pair.first; + auto lease = lease_params_pair.second; try { - if (!lease_addr.isV6Zero()) { + if (lease) { // This may throw if the lease couldn't be deleted for // any reason, but we still want to proceed with other // leases. - Lease6Ptr lease(new Lease6()); - lease->addr_ = lease_addr; - if (LeaseMgrFactory::instance().deleteLease(lease)) { ++success_count; @@ -1292,16 +1283,21 @@ LeaseCmdsImpl::lease6DelHandler(CalloutHandle& handle) { switch (p.query_type) { case Parameters::TYPE_ADDR: { - // If address was specified explicitly, let's use it as is. - addr = p.addr; + + // Let's see if there's such a lease at all. + lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, p.addr); + if (!lease6) { + setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY); + return (0); + } break; } - case Parameters::TYPE_HWADDR: + case Parameters::TYPE_HWADDR: { isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6."); break; - - case Parameters::TYPE_DUID: + } + case Parameters::TYPE_DUID: { if (!p.duid) { isc_throw(InvalidParameter, "Program error: Query by duid " "requires duid to be specified"); @@ -1314,21 +1310,15 @@ LeaseCmdsImpl::lease6DelHandler(CalloutHandle& handle) { setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY); return (0); } - - // Found it, can use it as is. - addr = lease6->addr_; break; - + } default: { isc_throw(InvalidOperation, "Unknown query type: " << static_cast(p.query_type)); break; } } - Lease6Ptr lease(new Lease6()); - lease->addr_ = addr; - - if (LeaseMgrFactory::instance().deleteLease(lease)) { + if (LeaseMgrFactory::instance().deleteLease(lease6)) { setSuccessResponse(handle, "IPv6 lease deleted."); } else { setErrorResponse (handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY); @@ -1509,23 +1499,28 @@ LeaseCmdsImpl::lease6WipeHandler(CalloutHandle& handle) { return (0); } -IOAddress -LeaseCmdsImpl::getIPv6AddressForDelete(const Parameters& parameters) const { - IOAddress addr = IOAddress::IPV6_ZERO_ADDRESS(); +Lease6Ptr +LeaseCmdsImpl::getIPv6LeaseForDelete(const Parameters& parameters) const { Lease6Ptr lease6; switch (parameters.query_type) { case Parameters::TYPE_ADDR: { - // If address was specified explicitly, let's use it as is. - addr = parameters.addr; + + // Let's see if there's such a lease at all. + lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type, + parameters.addr); + if (!lease6) { + lease6.reset(new Lease6()); + lease6->addr_ = parameters.addr; + } break; } - case Parameters::TYPE_HWADDR: + case Parameters::TYPE_HWADDR: { isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6."); break; - - case Parameters::TYPE_DUID: + } + case Parameters::TYPE_DUID: { if (!parameters.duid) { isc_throw(InvalidParameter, "Program error: Query by duid " "requires duid to be specified"); @@ -1536,18 +1531,14 @@ LeaseCmdsImpl::getIPv6AddressForDelete(const Parameters& parameters) const { *parameters.duid, parameters.iaid, parameters.subnet_id); - if (lease6) { - addr = lease6->addr_; - } - - break; - + break; + } default: isc_throw(InvalidOperation, "Unknown query type: " << static_cast(parameters.query_type)); } - return (addr); + return (lease6); } ElementPtr diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 136676dd3a..fd9ab7f1be 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -3674,8 +3675,8 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, // (the lease returned points directly to the lease4 object in the database) // We'll need it if we want to skip update (i.e. roll back renewal) /// @todo: remove this? - Lease4 old_values = *lease; - ctx.old_lease_.reset(new Lease4(old_values)); + Lease4Ptr old_values = boost::make_shared(*lease); + ctx.old_lease_.reset(new Lease4(*old_values)); // Update the lease with the information from the context. updateLease4Information(lease, ctx); @@ -3686,7 +3687,6 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, // involves execution of hooks and DNS update. if (ctx.old_lease_->expired()) { reclaimExpiredLease(ctx.old_lease_, ctx.callout_handle_); - } lease->state_ = Lease::STATE_DEFAULT; @@ -3756,7 +3756,7 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, if (skip) { // Rollback changes (really useful only for memfile) /// @todo: remove this? - *lease = old_values; + *lease = *old_values; } return (lease); diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 6ed7ce8ff1..2be3a07f5f 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -26,10 +26,11 @@ #include #include +#include using namespace isc::data; using namespace isc::db; -using isc::asiolink::IOAddress; +using namespace isc::asiolink; namespace isc { namespace dhcp { @@ -46,11 +47,12 @@ static constexpr char NULL_USER_CONTEXT[] = ""; /// base to both of them, containing some common methods. class CqlLeaseExchange : public CqlExchange { public: + /// @brief Constructor /// /// @param connection already open Cassandra connection. CqlLeaseExchange(const CqlConnection &connection) - : connection_(connection), valid_lifetime_(0), expire_(0), + : connection_(connection), valid_lifetime_(0), expire_(0), old_expire_(0), subnet_id_(0), fqdn_fwd_(cass_false), fqdn_rev_(cass_false), state_(0), user_context_(NULL_USER_CONTEXT) { } @@ -75,6 +77,7 @@ public: virtual boost::any retrieve() override = 0; protected: + /// @brief Database connection const CqlConnection &connection_; @@ -87,6 +90,9 @@ protected: /// @brief Lease expiry time cass_int64_t expire_; + /// @brief Expiration time of lease before update + cass_int64_t old_expire_; + /// @brief Subnet identifier cass_int32_t subnet_id_; @@ -120,6 +126,7 @@ protected: /// in all CqlLeaseMgr::xxx4() calls where it is used. class CqlLease4Exchange : public CqlLeaseExchange { public: + /// @brief Constructor /// /// The initialization of the variables here is only to satisfy @@ -236,6 +243,7 @@ public: /// @} private: + // Pointer to lease object Lease4Ptr lease_; // IPv4 address @@ -270,7 +278,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ ") VALUES ( " "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? " ") " - "IF NOT EXISTS "}}, + "IF NOT EXISTS " + }}, // Updates existing IPv4 lease {UPDATE_LEASE4, @@ -287,14 +296,16 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "state = ?, " "user_context = ? " "WHERE address = ? " - "IF EXISTS "}}, + "IF expire = ? " + }}, // Deletes existing IPv4 lease {DELETE_LEASE4, {DELETE_LEASE4, "DELETE FROM lease4 " "WHERE address = ? " - "IF EXISTS "}}, + "IF expire = ? " + }}, // Gets up to a certain number of expired IPv4 leases {GET_LEASE4_EXPIRE, @@ -307,7 +318,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "AND valid_lifetime < 4294967295 " "AND expire < ? " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv4 lease(s) {GET_LEASE4, @@ -315,7 +327,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "SELECT " "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, " "fqdn_fwd, fqdn_rev, hostname, state, user_context " - "FROM lease4 "}}, + "FROM lease4 " + }}, // Gets an IPv4 lease with specified IPv4 address {GET_LEASE4_ADDR, @@ -324,7 +337,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "address, hwaddr, client_id, valid_lifetime, expire, subnet_id, " "fqdn_fwd, fqdn_rev, hostname, state, user_context " "FROM lease4 " - "WHERE address = ? "}}, + "WHERE address = ? " + }}, // Gets an IPv4 lease(s) with specified client-id {GET_LEASE4_CLIENTID, @@ -334,7 +348,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "fqdn_fwd, fqdn_rev, hostname, state, user_context " "FROM lease4 " "WHERE client_id = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv4 lease with specified client-id and subnet-id {GET_LEASE4_CLIENTID_SUBID, @@ -345,7 +360,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "FROM lease4 " "WHERE client_id = ? " "AND subnet_id = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets all IPv4 leases with specified hardware address {GET_LEASE4_HWADDR, @@ -355,7 +371,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "fqdn_fwd, fqdn_rev, hostname, state, user_context " "FROM lease4 " "WHERE hwaddr = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv4 lease with specified hardware addr and subnet-id {GET_LEASE4_HWADDR_SUBID, @@ -366,7 +383,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "FROM lease4 " "WHERE hwaddr = ? " "AND subnet_id = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Get range of lease4 from first lease with a limit (paging) {GET_LEASE4_LIMIT, @@ -376,7 +394,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "fqdn_fwd, fqdn_rev, hostname, state, user_context " "FROM lease4 " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Get range of lease4 from address with a limit (paging) {GET_LEASE4_PAGE, @@ -387,7 +406,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "FROM lease4 " "WHERE TOKEN(address) > TOKEN(?) " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv4 lease(s) with specified subnet-id {GET_LEASE4_SUBID, @@ -407,7 +427,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{ "fqdn_fwd, fqdn_rev, hostname, state, user_context " "FROM lease4 " "WHERE hostname = ? " - "ALLOW FILTERING "}} + "ALLOW FILTERING " + }} }; CqlLease4Exchange::CqlLease4Exchange(const CqlConnection &connection) @@ -462,8 +483,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) { // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -565,8 +585,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -612,6 +631,8 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data, data.add(&user_context_); data.add(&address_); + CqlExchange::convertToDatabaseTime(lease_->old_cltt_, lease_->old_valid_lft_, old_expire_); + data.add(&old_expire_); } catch (const Exception &ex) { isc_throw(DbOperationError, "CqlLease4Exchange::createBindUpdate(): " @@ -640,6 +661,8 @@ CqlLease4Exchange::createBindForDelete(const Lease4Ptr &lease, AnyArray &data, data.clear(); data.add(&address_); + CqlExchange::convertToDatabaseTime(lease_->old_cltt_, lease_->old_valid_lft_, old_expire_); + data.add(&old_expire_); } catch (const Exception &ex) { isc_throw(DbOperationError, "CqlLease4Exchange::createBindForDelete(): " @@ -650,7 +673,6 @@ CqlLease4Exchange::createBindForDelete(const Lease4Ptr &lease, AnyArray &data, void CqlLease4Exchange::createBindForSelect(AnyArray &data, StatementTag /* unused */) { - // Start with a fresh array. data.clear(); @@ -718,7 +740,7 @@ CqlLease4Exchange::retrieve() { time_t cltt = 0; CqlExchange::convertFromDatabaseTime(expire_, valid_lifetime_, cltt); - HWAddrPtr hwaddr(new HWAddr(hwaddr_, HTYPE_ETHER)); + HWAddrPtr hwaddr = boost::make_shared(hwaddr_, HTYPE_ETHER); uint32_t addr4 = static_cast(address_); @@ -731,10 +753,10 @@ CqlLease4Exchange::retrieve() { } } - Lease4Ptr result(new Lease4(addr4, hwaddr, client_id_.data(), - client_id_.size(), valid_lifetime_, - cltt, subnet_id_, fqdn_fwd_, fqdn_rev_, - hostname_)); + Lease4Ptr result(boost::make_shared(addr4, hwaddr, client_id_.data(), + client_id_.size(), valid_lifetime_, + cltt, subnet_id_, fqdn_fwd_, fqdn_rev_, + hostname_)); result->state_ = state_; @@ -809,8 +831,7 @@ CqlLease4Exchange::getExpiredLeases(const size_t &max_leases, // Retrieve leases from the database. Lease4Collection temp_collection; - getLeaseCollection(CqlLease4Exchange::GET_LEASE4_EXPIRE, data, - temp_collection); + getLeaseCollection(CqlLease4Exchange::GET_LEASE4_EXPIRE, data, temp_collection); for (Lease4Ptr &lease : temp_collection) { expired_leases.push_back(lease); @@ -832,6 +853,7 @@ CqlLease4Exchange::getExpiredLeases(const size_t &max_leases, /// in all CqlLeaseMgr::xxx6() calls where it is used. class CqlLease6Exchange : public CqlLeaseExchange { public: + /// @brief Constructor /// /// The initialization of the variables here is only to satisfy @@ -931,6 +953,7 @@ public: // @} private: + /// @brief Lease Lease6Ptr lease_; @@ -983,7 +1006,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { ") VALUES (" "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" ") " - "IF NOT EXISTS "}}, + "IF NOT EXISTS " + }}, // Updates existing IPv6 lease {UPDATE_LEASE6, @@ -1006,14 +1030,16 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "state = ?, " "user_context = ? " "WHERE address = ? " - "IF EXISTS "}}, + "IF expire = ? " + }}, // Deletes existing IPv6 lease {DELETE_LEASE6, {DELETE_LEASE6, "DELETE FROM lease6 " "WHERE address = ? " - "IF EXISTS "}}, + "IF expire = ? " + }}, // Gets up to a certain number of expired IPv6 leases {GET_LEASE6_EXPIRE, @@ -1027,7 +1053,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "AND valid_lifetime < 4294967295 " "AND expire < ? " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv6 lease with specified IPv6 address {GET_LEASE6_ADDR, @@ -1039,7 +1066,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "FROM lease6 " "WHERE address = ? " "AND lease_type = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv6 lease with specified duid {GET_LEASE6_DUID, @@ -1050,7 +1078,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "hwaddr_source, state, user_context " "FROM lease6 " "WHERE duid = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv6 lease(s) with specified duid and iaid {GET_LEASE6_DUID_IAID, @@ -1062,7 +1091,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "FROM lease6 " "WHERE duid = ? AND iaid = ? " "AND lease_type = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv6 lease with specified duid, iaid and subnet-id {GET_LEASE6_DUID_IAID_SUBID, @@ -1075,7 +1105,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "WHERE duid = ? AND iaid = ? " "AND lease_type = ? " "AND subnet_id = ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Get range of IPv6 leases from first lease with a limit (paging) {GET_LEASE6_LIMIT, @@ -1086,7 +1117,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "hwaddr_source, state, user_context " "FROM lease6 " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Get range of IPv6 leases from address with a limit (paging) {GET_LEASE6_PAGE, @@ -1098,7 +1130,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "FROM lease6 " "WHERE TOKEN(address) > TOKEN(?) " "LIMIT ? " - "ALLOW FILTERING "}}, + "ALLOW FILTERING " + }}, // Gets an IPv6 lease(s) with specified hostname {GET_LEASE6_HOSTNAME, @@ -1109,9 +1142,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = { "hwaddr_source, state, user_context " "FROM lease6 " "WHERE hostname = ? " - "ALLOW FILTERING "}}, - - + "ALLOW FILTERING " + }} }; CqlLease6Exchange::CqlLease6Exchange(const CqlConnection &connection) @@ -1282,8 +1314,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, // For convenience for external tools, this is converted to lease // expiry time (expire). The relationship is given by: // expire = cltt_ + valid_lft_ - CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, - expire_); + CqlExchange::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_, expire_); // subnet_id: int subnet_id_ = static_cast(lease_->subnet_id_); @@ -1386,6 +1417,8 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data, data.add(&user_context_); data.add(&address_); + CqlExchange::convertToDatabaseTime(lease_->old_cltt_, lease_->old_valid_lft_, old_expire_); + data.add(&old_expire_); } catch (const Exception &ex) { isc_throw(DbOperationError, "CqlLease6Exchange::createBindForUpdate(): " @@ -1420,6 +1453,8 @@ CqlLease6Exchange::createBindForDelete(const Lease6Ptr &lease, AnyArray &data, data.clear(); data.add(&address_); + CqlExchange::convertToDatabaseTime(lease_->old_cltt_, lease_->old_valid_lft_, old_expire_); + data.add(&old_expire_); } catch (const Exception &ex) { isc_throw(DbOperationError, "CqlLease6Exchange::createBindForDelete(): " @@ -1430,7 +1465,6 @@ CqlLease6Exchange::createBindForDelete(const Lease6Ptr &lease, AnyArray &data, void CqlLease6Exchange::createBindForSelect(AnyArray &data, StatementTag /* unused */) { - // Start with a fresh array. data.clear(); @@ -1527,11 +1561,11 @@ CqlLease6Exchange::retrieve() { IOAddress addr(address_); - DuidPtr duid(new DUID(duid_)); + DuidPtr duid(boost::make_shared(duid_)); HWAddrPtr hwaddr; if (hwaddr_.size()) { - hwaddr.reset(new HWAddr(hwaddr_, hwtype_)); + hwaddr = boost::make_shared(hwaddr_, hwtype_); hwaddr->source_ = hwaddr_source_; } @@ -1546,14 +1580,15 @@ CqlLease6Exchange::retrieve() { // Create the lease and set the cltt (after converting from the // expire time retrieved from the database). - Lease6Ptr result(new Lease6(static_cast(lease_type_), addr, duid, - iaid_, pref_lifetime_, valid_lifetime_, - subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_, - hwaddr, prefix_len_)); + Lease6Ptr result(boost::make_shared(static_cast(lease_type_), addr, duid, + iaid_, pref_lifetime_, valid_lifetime_, + subnet_id_, fqdn_fwd_, fqdn_rev_, hostname_, + hwaddr, prefix_len_)); time_t cltt = 0; CqlExchange::convertFromDatabaseTime(expire_, valid_lifetime_, cltt); result->cltt_ = cltt; + result->old_cltt_ = cltt; result->state_ = state_; @@ -1629,8 +1664,7 @@ CqlLease6Exchange::getExpiredLeases(const size_t &max_leases, // Retrieve leases from the database. Lease6Collection temp_collection; - getLeaseCollection(CqlLease6Exchange::GET_LEASE6_EXPIRE, data, - temp_collection); + getLeaseCollection(CqlLease6Exchange::GET_LEASE6_EXPIRE, data, temp_collection); for (Lease6Ptr &lease : temp_collection) { expired_leases.push_back(lease); @@ -1645,6 +1679,7 @@ CqlLease6Exchange::getExpiredLeases(const size_t &max_leases, /// class CqlLeaseStatsQuery : public LeaseStatsQuery { public: + /// @brief Constructor to query for all subnets' stats /// /// The query created will return statistics for all subnets @@ -1781,6 +1816,7 @@ public: static StatementMap tagged_statements_; private: + /// @brief Database connection to use to execute the query CqlConnection& conn_; @@ -2047,7 +2083,7 @@ CqlLeaseStatsQuery::executeSelect(const CqlConnection& connection, const AnyArra } CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap ¶meters) - : LeaseMgr(), parameters_(parameters), dbconn_(parameters) { + : parameters_(parameters), dbconn_(parameters) { // Validate the schema version first. std::pair code_version(CQL_SCHEMA_VERSION_MAJOR, CQL_SCHEMA_VERSION_MINOR); @@ -2098,6 +2134,10 @@ CqlLeaseMgr::addLease(const Lease4Ptr &lease) { .arg(exception.what()); return false; } + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + return true; } @@ -2117,6 +2157,10 @@ CqlLeaseMgr::addLease(const Lease6Ptr &lease) { .arg(exception.what()); return false; } + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + return true; } @@ -2563,6 +2607,9 @@ CqlLeaseMgr::updateLease4(const Lease4Ptr &lease) { } catch (const StatementNotApplied &exception) { isc_throw(NoSuchLease, exception.what()); } + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } void @@ -2579,6 +2626,9 @@ CqlLeaseMgr::updateLease6(const Lease6Ptr &lease) { } catch (const StatementNotApplied &exception) { isc_throw(NoSuchLease, exception.what()); } + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } bool diff --git a/src/lib/dhcpsrv/cql_lease_mgr.h b/src/lib/dhcpsrv/cql_lease_mgr.h index cb20819500..b14991c0a3 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.h +++ b/src/lib/dhcpsrv/cql_lease_mgr.h @@ -41,6 +41,7 @@ namespace dhcp { /// and that the Kea schema has been created within it. class CqlLeaseMgr : public LeaseMgr { public: + /// @brief Constructor /// /// Uses the following keywords in the parameters passed to it to @@ -581,6 +582,7 @@ public: virtual void rollback() override; private: + /// @brief Connection parameters db::DatabaseConnection::ParameterMap parameters_; diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc index 3ac260af7b..a175b58d96 100644 --- a/src/lib/dhcpsrv/lease.cc +++ b/src/lib/dhcpsrv/lease.cc @@ -40,9 +40,10 @@ Lease::Lease(const isc::asiolink::IOAddress& addr, uint32_t valid_lft, SubnetID subnet_id, time_t cltt, const bool fqdn_fwd, const bool fqdn_rev, const std::string& hostname, const HWAddrPtr& hwaddr) - :addr_(addr), valid_lft_(valid_lft), cltt_(cltt), subnet_id_(subnet_id), - hostname_(boost::algorithm::to_lower_copy(hostname)), fqdn_fwd_(fqdn_fwd), - fqdn_rev_(fqdn_rev), hwaddr_(hwaddr), state_(STATE_DEFAULT) { + : addr_(addr), valid_lft_(valid_lft), old_valid_lft_(valid_lft), + cltt_(cltt), old_cltt_(cltt), subnet_id_(subnet_id), + hostname_(boost::algorithm::to_lower_copy(hostname)), fqdn_fwd_(fqdn_fwd), + fqdn_rev_(fqdn_rev), hwaddr_(hwaddr), state_(STATE_DEFAULT) { } @@ -376,7 +377,9 @@ Lease4::operator=(const Lease4& other) { if (this != &other) { addr_ = other.addr_; valid_lft_ = other.valid_lft_; + old_valid_lft_ = other.old_valid_lft_; cltt_ = other.cltt_; + old_cltt_ = other.old_cltt_; subnet_id_ = other.subnet_id_; hostname_ = other.hostname_; fqdn_fwd_ = other.fqdn_fwd_; @@ -477,6 +480,7 @@ Lease6::Lease6(Lease::Type type, const isc::asiolink::IOAddress& addr, } cltt_ = time(NULL); + old_cltt_ = cltt_; } Lease6::Lease6(Lease::Type type, const isc::asiolink::IOAddress& addr, @@ -493,6 +497,7 @@ Lease6::Lease6(Lease::Type type, const isc::asiolink::IOAddress& addr, } cltt_ = time(NULL); + old_cltt_ = cltt_; } Lease6::Lease6() @@ -581,7 +586,9 @@ Lease4::operator==(const Lease4& other) const { addr_ == other.addr_ && subnet_id_ == other.subnet_id_ && valid_lft_ == other.valid_lft_ && + old_valid_lft_ == other.old_valid_lft_ && cltt_ == other.cltt_ && + old_cltt_ == other.old_cltt_ && hostname_ == other.hostname_ && fqdn_fwd_ == other.fqdn_fwd_ && fqdn_rev_ == other.fqdn_rev_ && @@ -599,7 +606,9 @@ Lease6::operator==(const Lease6& other) const { iaid_ == other.iaid_ && preferred_lft_ == other.preferred_lft_ && valid_lft_ == other.valid_lft_ && + old_valid_lft_ == other.old_valid_lft_ && cltt_ == other.cltt_ && + old_cltt_ == other.old_cltt_ && subnet_id_ == other.subnet_id_ && hostname_ == other.hostname_ && fqdn_fwd_ == other.fqdn_fwd_ && diff --git a/src/lib/dhcpsrv/lease.h b/src/lib/dhcpsrv/lease.h index 7354e2fa69..a1fdc94ebe 100644 --- a/src/lib/dhcpsrv/lease.h +++ b/src/lib/dhcpsrv/lease.h @@ -116,12 +116,23 @@ struct Lease : public isc::data::UserContext, public isc::data::CfgToElement { /// Expressed as number of seconds since cltt. uint32_t valid_lft_; + /// @brief Old valid lifetime + /// + /// Expressed as number of seconds since cltt before update. + uint32_t old_valid_lft_; + /// @brief Client last transmission time /// /// Specifies a timestamp giving the time when the last transmission from a /// client was received. time_t cltt_; + /// @brief Old client last transmission time + /// + /// Specifies a timestamp giving the time when the last transmission from a + /// client was received before update. + time_t old_cltt_; + /// @brief Subnet identifier /// /// Specifies the identification of the subnet to which the lease belongs. diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index ec399f75f9..2ec44e818c 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -95,12 +96,12 @@ const size_t USER_CONTEXT_MAX_LEN = 8192; boost::array tagged_statements = { { {MySqlLeaseMgr::DELETE_LEASE4, - "DELETE FROM lease4 WHERE address = ?"}, + "DELETE FROM lease4 WHERE address = ? AND expire = ?"}, {MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED, "DELETE FROM lease4 " "WHERE state = ? AND expire < ?"}, {MySqlLeaseMgr::DELETE_LEASE6, - "DELETE FROM lease6 WHERE address = ?"}, + "DELETE FROM lease6 WHERE address = ? AND expire = ?"}, {MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED, "DELETE FROM lease6 " "WHERE state = ? AND expire < ?"}, @@ -286,7 +287,7 @@ tagged_statements = { { "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, " "hostname = ?, " "state = ?, user_context = ? " - "WHERE address = ?"}, + "WHERE address = ? AND expire = ?"}, {MySqlLeaseMgr::UPDATE_LEASE6, "UPDATE lease6 SET address = ?, duid = ?, " "valid_lifetime = ?, expire = ?, subnet_id = ?, " @@ -294,38 +295,33 @@ tagged_statements = { { "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, " "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, " "state = ?, user_context = ? " - "WHERE address = ?"}, + "WHERE address = ? AND expire = ?"}, {MySqlLeaseMgr::ALL_LEASE4_STATS, - "SELECT subnet_id, state, leases as state_count" - " FROM lease4_stat ORDER BY subnet_id, state"}, - + "SELECT subnet_id, state, leases as state_count " + "FROM lease4_stat ORDER BY subnet_id, state"}, {MySqlLeaseMgr::SUBNET_LEASE4_STATS, - "SELECT subnet_id, state, leases as state_count" - " FROM lease4_stat " - " WHERE subnet_id = ? " - " ORDER BY state"}, - + "SELECT subnet_id, state, leases as state_count " + "FROM lease4_stat " + "WHERE subnet_id = ? " + "ORDER BY state"}, {MySqlLeaseMgr::SUBNET_RANGE_LEASE4_STATS, - "SELECT subnet_id, state, leases as state_count" - " FROM lease4_stat " - " WHERE subnet_id >= ? and subnet_id <= ? " - " ORDER BY subnet_id, state"}, - + "SELECT subnet_id, state, leases as state_count " + "FROM lease4_stat " + "WHERE subnet_id >= ? and subnet_id <= ? " + "ORDER BY subnet_id, state"}, {MySqlLeaseMgr::ALL_LEASE6_STATS, - "SELECT subnet_id, lease_type, state, leases as state_count" - " FROM lease6_stat ORDER BY subnet_id, lease_type, state" }, - + "SELECT subnet_id, lease_type, state, leases as state_count " + "FROM lease6_stat ORDER BY subnet_id, lease_type, state"}, {MySqlLeaseMgr::SUBNET_LEASE6_STATS, - "SELECT subnet_id, lease_type, state, leases as state_count" - " FROM lease6_stat " - " WHERE subnet_id = ? " - " ORDER BY lease_type, state" }, - + "SELECT subnet_id, lease_type, state, leases as state_count " + "FROM lease6_stat " + "WHERE subnet_id = ? " + "ORDER BY lease_type, state"}, {MySqlLeaseMgr::SUBNET_RANGE_LEASE6_STATS, - "SELECT subnet_id, lease_type, state, leases as state_count" - " FROM lease6_stat " - " WHERE subnet_id >= ? and subnet_id <= ? " - " ORDER BY subnet_id, lease_type, state" } + "SELECT subnet_id, lease_type, state, leases as state_count " + "FROM lease6_stat " + "WHERE subnet_id >= ? and subnet_id <= ? " + "ORDER BY subnet_id, lease_type, state"} } }; @@ -343,6 +339,7 @@ namespace dhcp { class MySqlLeaseExchange { public: + /// @brief Set error indicators /// /// Sets the error indicator for each of the MYSQL_BIND elements. It points @@ -419,6 +416,7 @@ class MySqlLease4Exchange : public MySqlLeaseExchange { static const size_t LEASE_COLUMNS = 11; public: + /// @brief Constructor /// /// The initialization of the variables here is only to satisfy cppcheck - @@ -649,7 +647,6 @@ public: /// Creates a MYSQL_BIND array to receive Lease4 data from the database. /// After data is successfully received, getLeaseData() can be used to copy /// it to a Lease6 object. - /// std::vector createBindForReceive() { // Initialize MYSQL_BIND array. @@ -756,7 +753,7 @@ public: // Add the data to the vector. Note the end element is one after the // end of the array. - return(std::vector(&bind_[0], &bind_[LEASE_COLUMNS])); + return (std::vector(&bind_[0], &bind_[LEASE_COLUMNS])); } /// @brief Copy Received Data into Lease4 Object @@ -788,7 +785,7 @@ public: std::string hostname(hostname_buffer_, hostname_buffer_ + hostname_length_); - /// Set hardware address if it was set + // Set hardware address if it was set HWAddrPtr hwaddr; if (hwaddr_null_ == MLM_FALSE) { hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER)); @@ -811,9 +808,12 @@ public: } } - Lease4Ptr lease(new Lease4(addr4_, hwaddr, client_id_buffer_, - client_id_length_, valid_lifetime_, cltt, - subnet_id_, fqdn_fwd_, fqdn_rev_, hostname)); + Lease4Ptr lease(boost::make_shared(addr4_, hwaddr, + client_id_buffer_, + client_id_length_, + valid_lifetime_, cltt, + subnet_id_, fqdn_fwd_, + fqdn_rev_, hostname)); // Set state. lease->state_ = state_; @@ -844,30 +844,30 @@ private: // Note: All array lengths are equal to the corresponding variable in the // schema. // Note: Arrays are declared fixed length for speed of creation - uint32_t addr4_; ///< IPv4 address - MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS]; ///< Column names - my_bool error_[LEASE_COLUMNS]; ///< Error array - std::vector hwaddr_; ///< Hardware address - uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer - unsigned long hwaddr_length_; ///< Hardware address length - my_bool hwaddr_null_; ///< Used when HWAddr is null - std::vector client_id_; ///< Client identification - uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Client ID buffer - unsigned long client_id_length_; ///< Client ID address length - my_bool client_id_null_; ///< Is Client ID null? - MYSQL_TIME expire_; ///< Lease expiry time - Lease4Ptr lease_; ///< Pointer to lease object - uint32_t subnet_id_; ///< Subnet identification - uint32_t valid_lifetime_; ///< Lease time - my_bool fqdn_fwd_; ///< Has forward DNS update been performed - my_bool fqdn_rev_; ///< Has reverse DNS update been performed - char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname - unsigned long hostname_length_; ///< Client hostname length - uint32_t state_; ///< Lease state - char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context - unsigned long user_context_length_; ///< User context length - my_bool user_context_null_; ///< Is user context null? + uint32_t addr4_; ///< IPv4 address + MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array + std::string columns_[LEASE_COLUMNS]; ///< Column names + my_bool error_[LEASE_COLUMNS]; ///< Error array + Lease4Ptr lease_; ///< Pointer to lease object + std::vector hwaddr_; ///< Hardware address + uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer + unsigned long hwaddr_length_; ///< Length of Hardware address + my_bool hwaddr_null_; ///< Used when Hardware address is null + std::vector client_id_; ///< Client identification + uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Client ID buffer + unsigned long client_id_length_; ///< Client ID address length + my_bool client_id_null_; ///< Used when Client ID is null + MYSQL_TIME expire_; ///< Lease expire time + uint32_t subnet_id_; ///< Subnet identification + uint32_t valid_lifetime_; ///< Lease time + my_bool fqdn_fwd_; ///< Has forward DNS update been performed + my_bool fqdn_rev_; ///< Has reverse DNS update been performed + char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname + unsigned long hostname_length_; ///< Length of client hostname + uint32_t state_; ///< Lease state + char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context + unsigned long user_context_length_; ///< Length of user context + my_bool user_context_null_; ///< Used when user context is null }; /// @brief Exchange MySQL and Lease6 Data @@ -888,16 +888,17 @@ class MySqlLease6Exchange : public MySqlLeaseExchange { static const size_t LEASE_COLUMNS = 17; public: + /// @brief Constructor /// /// The initialization of the variables here is only to satisfy cppcheck - /// all variables are initialized/set in the methods before they are used. - MySqlLease6Exchange() : addr6_length_(0), duid_length_(0), - iaid_(0), lease_type_(0), prefixlen_(0), + MySqlLease6Exchange() : addr6_length_(0), hwaddr_length_(0), + hwaddr_null_(MLM_FALSE), duid_length_(0), + iaid_(0), lease_type_(0), prefix_len_(0), pref_lifetime_(0), subnet_id_(0), valid_lifetime_(0), fqdn_fwd_(false), fqdn_rev_(false), - hostname_length_(0), hwaddr_length_(0), - hwaddr_null_(MLM_FALSE), hwtype_(0), hwaddr_source_(0), + hostname_length_(0), hwtype_(0), hwaddr_source_(0), state_(0), user_context_length_(0), user_context_null_(MLM_FALSE) { memset(addr6_buffer_, 0, sizeof(addr6_buffer_)); @@ -999,7 +1000,7 @@ public: // expire: timestamp // The lease structure holds the client last transmission time (cltt_) // For convenience for external tools, this is converted to lease - /// expiry time (expire). The relationship is given by: + // expiry time (expire). The relationship is given by: // // expire = cltt_ + valid_lft_ // Avoid overflow @@ -1108,7 +1109,7 @@ public: bind_[12].is_null = &hwaddr_null_; } - // hwtype + // hardware source: unsigned int (32 bits) if (hwaddr) { hwtype_ = lease->hwaddr_->htype_; bind_[13].buffer_type = MYSQL_TYPE_SHORT; @@ -1127,7 +1128,7 @@ public: bind_[13].is_null = &hwaddr_null_; } - /// Hardware source + // hardware source: unsigned int (32 bits) if (hwaddr) { hwaddr_source_ = lease->hwaddr_->source_; bind_[14].buffer_type = MYSQL_TYPE_LONG; @@ -1266,7 +1267,7 @@ public: // prefix_len: unsigned tinyint bind_[8].buffer_type = MYSQL_TYPE_TINY; - bind_[8].buffer = reinterpret_cast(&prefixlen_); + bind_[8].buffer = reinterpret_cast(&prefix_len_); bind_[8].is_unsigned = MLM_TRUE; // bind_[8].is_null = &MLM_FALSE; // commented out for performance // reasons, see memset() above @@ -1337,7 +1338,7 @@ public: // Add the data to the vector. Note the end element is one after the // end of the array. - return(std::vector(&bind_[0], &bind_[LEASE_COLUMNS])); + return (std::vector(&bind_[0], &bind_[LEASE_COLUMNS])); } /// @brief Copy Received Data into Lease6 Object @@ -1389,7 +1390,7 @@ public: std::string hostname(hostname_buffer_, hostname_buffer_ + hostname_length_); - /// Set hardware address if it was set + // Set hardware address if it was set HWAddrPtr hwaddr; if (hwaddr_null_ == MLM_FALSE) { hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_)); @@ -1415,10 +1416,12 @@ public: // Create the lease and set the cltt (after converting from the // expire time retrieved from the database). - Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_, - pref_lifetime_, valid_lifetime_, - subnet_id_, fqdn_fwd_, fqdn_rev_, - hostname, hwaddr, prefixlen_)); + Lease6Ptr result(boost::make_shared(type, addr, duid_ptr, iaid_, + pref_lifetime_, + valid_lifetime_, subnet_id_, + fqdn_fwd_, fqdn_rev_, + hostname, hwaddr, + prefix_len_)); time_t cltt = 0; // Recover from overflow uint32_t valid_lft = valid_lifetime_; @@ -1427,6 +1430,7 @@ public: } MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt); result->cltt_ = cltt; + result->old_cltt_ = cltt; // Set state. result->state_ = state_; @@ -1453,41 +1457,41 @@ public: } private: + // Note: All array lengths are equal to the corresponding variable in the // schema. // Note: arrays are declared fixed length for speed of creation - std::string addr6_; ///< String form of address - char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character - ///< array form of V6 address - unsigned long addr6_length_; ///< Length of the address - MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array - std::string columns_[LEASE_COLUMNS]; ///< Column names - std::vector duid_; ///< Client identification - uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID - unsigned long duid_length_; ///< Length of the DUID - my_bool error_[LEASE_COLUMNS]; ///< Error indicators - MYSQL_TIME expire_; ///< Lease expiry time - uint32_t iaid_; ///< Identity association ID - Lease6Ptr lease_; ///< Pointer to lease object - uint8_t lease_type_; ///< Lease type - uint8_t prefixlen_; ///< Prefix length - uint32_t pref_lifetime_; ///< Preferred lifetime - uint32_t subnet_id_; ///< Subnet identification - uint32_t valid_lifetime_; ///< Lease time - my_bool fqdn_fwd_; ///< Has forward DNS update been performed - my_bool fqdn_rev_; ///< Has reverse DNS update been performed - char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname - unsigned long hostname_length_; ///< Client hostname length - uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Buffer form of Hardware address - std::vector hwaddr_; ///< Hardware address (optional) - unsigned long hwaddr_length_; ///< Aux. variable denoting hwaddr_ size() - my_bool hwaddr_null_; ///< Used when HWAddr is null - uint16_t hwtype_; ///< Hardware type - uint32_t hwaddr_source_; ///< Source of the hardware address - uint32_t state_; ///< Lease state. - char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context - unsigned long user_context_length_; ///< User context length - my_bool user_context_null_; ///< Is user context null? + std::string addr6_; ///< Address + char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Address buffer + unsigned long addr6_length_; ///< Length of address + MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array + std::string columns_[LEASE_COLUMNS]; ///< Column names + my_bool error_[LEASE_COLUMNS]; ///< Error array + Lease6Ptr lease_; ///< Pointer to lease object + std::vector hwaddr_; ///< Hardware address + uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer + unsigned long hwaddr_length_; ///< Length of Hardware address + my_bool hwaddr_null_; ///< Used when Hardware address is null + std::vector duid_; ///< DUID + uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< DUID buffer + unsigned long duid_length_; ///< Length of DUID + MYSQL_TIME expire_; ///< Lease expire time + uint32_t iaid_; ///< Identity association ID + uint8_t lease_type_; ///< Lease type + uint8_t prefix_len_; ///< Prefix length + uint32_t pref_lifetime_; ///< Preferred lifetime + uint32_t subnet_id_; ///< Subnet identification + uint32_t valid_lifetime_; ///< Lease time + my_bool fqdn_fwd_; ///< Has forward DNS update been performed + my_bool fqdn_rev_; ///< Has reverse DNS update been performed + char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname + unsigned long hostname_length_; ///< Length of client hostname + uint16_t hwtype_; ///< Hardware type + uint32_t hwaddr_source_; ///< Source of the hardware address + uint32_t state_; ///< Lease state + char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context + unsigned long user_context_length_; ///< Length of user context + my_bool user_context_null_; ///< Used when user context is null }; /// @brief MySql derivation of the statistical lease data query @@ -1499,6 +1503,7 @@ private: /// class MySqlLeaseStatsQuery : public LeaseStatsQuery { public: + /// @brief Constructor to query for all subnets' stats /// /// The query created will return statistics for all subnets @@ -1669,6 +1674,7 @@ public: } private: + /// @brief Validate the statement index passed to the constructor /// Safely fetch the statement from the connection based on statement index /// @throw BadValue if statement index is out of range @@ -1698,10 +1704,13 @@ private: /// @brief Receives subnet ID when fetching a row uint32_t subnet_id_; + /// @brief Receives the lease type when fetching a row uint32_t lease_type_; + /// @brief Receives the lease state when fetching a row uint32_t state_; + /// @brief Receives the state count when fetching a row int64_t state_count_; }; @@ -1854,7 +1863,12 @@ MySqlLeaseMgr::addLease(const Lease4Ptr& lease) { std::vector bind = ctx->exchange4_->createBindForSend(lease); // ... and drop to common code. - return (addLeaseCommon(ctx, INSERT_LEASE4, bind)); + auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + + return (result); } bool @@ -1871,7 +1885,12 @@ MySqlLeaseMgr::addLease(const Lease6Ptr& lease) { std::vector bind = ctx->exchange6_->createBindForSend(lease); // ... and drop to common code. - return (addLeaseCommon(ctx, INSERT_LEASE6, bind)); + auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + + return (result); } // Extraction of leases from the database. @@ -1900,12 +1919,13 @@ MySqlLeaseMgr::addLease(const Lease6Ptr& lease) { // holding zero or one leases into an appropriate Lease object. template -void MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr ctx, - StatementIndex stindex, - MYSQL_BIND* bind, - Exchange& exchange, - LeaseCollection& result, - bool single) const { +void +MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr ctx, + StatementIndex stindex, + MYSQL_BIND* bind, + Exchange& exchange, + LeaseCollection& result, + bool single) const { int status; @@ -1964,9 +1984,10 @@ void MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr ctx, } } -void MySqlLeaseMgr::getLease(MySqlLeaseContextPtr ctx, - StatementIndex stindex, MYSQL_BIND* bind, - Lease4Ptr& result) const { +void +MySqlLeaseMgr::getLease(MySqlLeaseContextPtr ctx, + StatementIndex stindex, MYSQL_BIND* bind, + Lease4Ptr& result) const { // Create appropriate collection object and get all leases matching // the selection criteria. The "single" parameter is true to indicate // that the called method should throw an exception if multiple @@ -1983,9 +2004,10 @@ void MySqlLeaseMgr::getLease(MySqlLeaseContextPtr ctx, } } -void MySqlLeaseMgr::getLease(MySqlLeaseContextPtr ctx, - StatementIndex stindex, MYSQL_BIND* bind, - Lease6Ptr& result) const { +void +MySqlLeaseMgr::getLease(MySqlLeaseContextPtr ctx, + StatementIndex stindex, MYSQL_BIND* bind, + Lease6Ptr& result) const { // Create appropriate collection object and get all leases matching // the selection criteria. The "single" parameter is true to indicate // that the called method should throw an exception if multiple @@ -2686,15 +2708,22 @@ MySqlLeaseMgr::updateLeaseCommon(MySqlLeaseContextPtr ctx, // See how many rows were affected. The statement should only update a // single row. int affected_rows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]); + + // Check success case first as it is the most likely outcome. + if (affected_rows == 1) { + return; + } + + // If no rows affected, lease doesn't exist. if (affected_rows == 0) { isc_throw(NoSuchLease, "unable to update lease for address " << - lease->addr_ << " as it does not exist"); - } else if (affected_rows > 1) { - // Should not happen - primary key constraint should only have selected - // one row. - isc_throw(DbOperationError, "apparently updated more than one lease " - "that had the address " << lease->addr_); + lease->addr_.toText() << " as it does not exist"); } + + // Should not happen - primary key constraint should only have selected + // one row. + isc_throw(DbOperationError, "apparently updated more than one lease " + "that had the address " << lease->addr_.toText()); } void @@ -2712,17 +2741,30 @@ MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { std::vector bind = ctx->exchange4_->createBindForSend(lease); // Set up the WHERE clause and append it to the MYSQL_BIND array - MYSQL_BIND where; - memset(&where, 0, sizeof(where)); + MYSQL_BIND inbind[2]; + memset(inbind, 0, sizeof(inbind)); uint32_t addr4 = lease->addr_.toUint32(); - where.buffer_type = MYSQL_TYPE_LONG; - where.buffer = reinterpret_cast(&addr4); - where.is_unsigned = MLM_TRUE; - bind.push_back(where); + inbind[0].buffer_type = MYSQL_TYPE_LONG; + inbind[0].buffer = reinterpret_cast(&addr4); + inbind[0].is_unsigned = MLM_TRUE; + + bind.push_back(inbind[0]); + + MYSQL_TIME expire; + MySqlConnection::convertToDatabaseTime(lease->old_cltt_, lease->old_valid_lft_, + expire); + inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP; + inbind[1].buffer = reinterpret_cast(&expire); + inbind[1].buffer_length = sizeof(expire); + + bind.push_back(inbind[1]); // Drop to common update code updateLeaseCommon(ctx, stindex, &bind[0], lease); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } void @@ -2740,23 +2782,36 @@ MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) { // Create the MYSQL_BIND array for the data being updated std::vector bind = ctx->exchange6_->createBindForSend(lease); - // Set up the WHERE clause value - MYSQL_BIND where; - memset(&where, 0, sizeof(where)); + // Set up the WHERE clause and append it to the MYSQL_BIND array + MYSQL_BIND inbind[2]; + memset(inbind, 0, sizeof(inbind)); std::string addr6 = lease->addr_.toText(); unsigned long addr6_length = addr6.size(); // See the earlier description of the use of "const_cast" when accessing // the address for an explanation of the reason. - where.buffer_type = MYSQL_TYPE_STRING; - where.buffer = const_cast(addr6.c_str()); - where.buffer_length = addr6_length; - where.length = &addr6_length; - bind.push_back(where); + inbind[0].buffer_type = MYSQL_TYPE_STRING; + inbind[0].buffer = const_cast(addr6.c_str()); + inbind[0].buffer_length = addr6_length; + inbind[0].length = &addr6_length; + + bind.push_back(inbind[0]); + + MYSQL_TIME expire; + MySqlConnection::convertToDatabaseTime(lease->old_cltt_, lease->old_valid_lft_, + expire); + inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP; + inbind[1].buffer = reinterpret_cast(&expire); + inbind[1].buffer_length = sizeof(expire); + + bind.push_back(inbind[1]); // Drop to common update code updateLeaseCommon(ctx, stindex, &bind[0], lease); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } // Delete lease methods. Similar to other groups of methods, these comprise @@ -2791,7 +2846,7 @@ MySqlLeaseMgr::deleteLease(const Lease4Ptr& lease) { .arg(addr.toText()); // Set up the WHERE clause value - MYSQL_BIND inbind[1]; + MYSQL_BIND inbind[2]; memset(inbind, 0, sizeof(inbind)); uint32_t addr4 = addr.toUint32(); @@ -2800,6 +2855,13 @@ MySqlLeaseMgr::deleteLease(const Lease4Ptr& lease) { inbind[0].buffer = reinterpret_cast(&addr4); inbind[0].is_unsigned = MLM_TRUE; + MYSQL_TIME expire; + MySqlConnection::convertToDatabaseTime(lease->old_cltt_, lease->old_valid_lft_, + expire); + inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP; + inbind[1].buffer = reinterpret_cast(&expire); + inbind[1].buffer_length = sizeof(expire); + return (deleteLeaseCommon(DELETE_LEASE4, inbind) > 0); } @@ -2811,7 +2873,7 @@ MySqlLeaseMgr::deleteLease(const Lease6Ptr& lease) { .arg(addr.toText()); // Set up the WHERE clause value - MYSQL_BIND inbind[1]; + MYSQL_BIND inbind[2]; memset(inbind, 0, sizeof(inbind)); std::string addr6 = addr.toText(); @@ -2824,6 +2886,13 @@ MySqlLeaseMgr::deleteLease(const Lease6Ptr& lease) { inbind[0].buffer_length = addr6_length; inbind[0].length = &addr6_length; + MYSQL_TIME expire; + MySqlConnection::convertToDatabaseTime(lease->old_cltt_, lease->old_valid_lft_, + expire); + inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP; + inbind[1].buffer = reinterpret_cast(&expire); + inbind[1].buffer_length = sizeof(expire); + return (deleteLeaseCommon(DELETE_LEASE6, inbind) > 0); } diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h index c638f5c8ce..2bfc1790ef 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -667,6 +667,7 @@ public: }; private: + /// @brief Add Lease Common Code /// /// This method performs the common actions for both flavours (V4 and V6) @@ -899,6 +900,7 @@ private: MySqlLeaseContextPtr ctx_; private: + /// @brief The manager const MySqlLeaseMgr& mgr_; }; diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 4306a9815e..a63830bfac 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -28,7 +29,6 @@ using namespace isc::db; using namespace isc::dhcp; using namespace isc::data; using namespace isc::util; -using namespace std; namespace { @@ -37,9 +37,9 @@ namespace { /// that the occur in the table. This does not apply to the where clause. PgSqlTaggedStatement tagged_statements[] = { // DELETE_LEASE4 - { 1, { OID_INT8 }, + { 2, { OID_INT8, OID_TIMESTAMP }, "delete_lease4", - "DELETE FROM lease4 WHERE address = $1"}, + "DELETE FROM lease4 WHERE address = $1 AND expire = $2"}, // DELETE_LEASE4_STATE_EXPIRED { 2, { OID_INT8, OID_TIMESTAMP }, @@ -48,9 +48,9 @@ PgSqlTaggedStatement tagged_statements[] = { "WHERE state = $1 AND expire < $2"}, // DELETE_LEASE6 - { 1, { OID_VARCHAR }, + { 2, { OID_VARCHAR, OID_TIMESTAMP }, "delete_lease6", - "DELETE FROM lease6 WHERE address = $1"}, + "DELETE FROM lease6 WHERE address = $1 AND expire = $2"}, // DELETE_LEASE6_STATE_EXPIRED { 2, { OID_INT8, OID_TIMESTAMP }, @@ -287,20 +287,20 @@ PgSqlTaggedStatement tagged_statements[] = { "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"}, // UPDATE_LEASE4 - { 12, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, - OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_INT8 }, + { 13, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, + OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_INT8, OID_TIMESTAMP }, "update_lease4", "UPDATE lease4 SET address = $1, hwaddr = $2, " "client_id = $3, valid_lifetime = $4, expire = $5, " "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, " "state = $10, user_context = $11 " - "WHERE address = $12"}, + "WHERE address = $12 AND expire = $13"}, // UPDATE_LEASE6 - { 18, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8, + { 19, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8, OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL, OID_VARCHAR, OID_BYTEA, OID_INT2, OID_INT2, - OID_INT8, OID_TEXT, OID_VARCHAR }, + OID_INT8, OID_TEXT, OID_VARCHAR, OID_TIMESTAMP }, "update_lease6", "UPDATE lease6 SET address = $1, duid = $2, " "valid_lifetime = $3, expire = $4, subnet_id = $5, " @@ -308,7 +308,7 @@ PgSqlTaggedStatement tagged_statements[] = { "prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, " "hwaddr = $13, hwtype = $14, hwaddr_source = $15, " "state = $16, user_context = $17 " - "WHERE address = $18"}, + "WHERE address = $18 AND expire = $19"}, // ALL_LEASE4_STATS { 0, { OID_NONE }, @@ -369,31 +369,37 @@ namespace dhcp { /// database. class PgSqlLeaseExchange : public PgSqlExchange { public: + PgSqlLeaseExchange() - : addr_str_(""), valid_lifetime_(0), valid_lifetime_str_(""), - expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""), - cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), - state_str_(""), user_context_("") { + : addr_str_(""), hwaddr_length_(0), hwaddr_(hwaddr_length_), + valid_lifetime_(0), valid_lifetime_str_(""), expire_(0), + expire_str_(""), subnet_id_(0), subnet_id_str_(""), cltt_(0), + fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), state_str_(""), + user_context_("") { } virtual ~PgSqlLeaseExchange(){} protected: + /// @brief Common Instance members used for binding and conversion //@{ - std::string addr_str_; - uint32_t valid_lifetime_; - std::string valid_lifetime_str_; - time_t expire_; - std::string expire_str_; - uint32_t subnet_id_; - std::string subnet_id_str_; - time_t cltt_; - bool fqdn_fwd_; - bool fqdn_rev_; - std::string hostname_; - std::string state_str_; - std::string user_context_; + std::string addr_str_; + size_t hwaddr_length_; + std::vector hwaddr_; + uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; + uint32_t valid_lifetime_; + std::string valid_lifetime_str_; + time_t expire_; + std::string expire_str_; + uint32_t subnet_id_; + std::string subnet_id_str_; + time_t cltt_; + bool fqdn_fwd_; + bool fqdn_rev_; + std::string hostname_; + std::string state_str_; + std::string user_context_; //@} }; @@ -423,8 +429,7 @@ public: /// @brief Constructor PgSqlLease4Exchange() - : lease_(), addr4_(0), hwaddr_length_(0), hwaddr_(hwaddr_length_), - client_id_length_(0) { + : lease_(), addr4_(0), client_id_length_(0) { BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS); @@ -466,8 +471,7 @@ public: lease_ = lease; try { - addr_str_ = boost::lexical_cast - (lease->addr_.toUint32()); + addr_str_ = boost::lexical_cast(lease->addr_.toUint32()); bind_array.add(addr_str_); if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) { @@ -521,7 +525,6 @@ public: user_context_ = ""; } bind_array.add(user_context_); - } catch (const std::exception& ex) { isc_throw(DbOperationError, "Could not create bind array from Lease4: " @@ -583,12 +586,12 @@ public: } } - Lease4Ptr result(new Lease4(addr4_, hwaddr, - client_id_buffer_, - client_id_length_, - valid_lifetime_, cltt_, - subnet_id_, fqdn_fwd_, - fqdn_rev_, hostname_)); + Lease4Ptr result(boost::make_shared(addr4_, hwaddr, + client_id_buffer_, + client_id_length_, + valid_lifetime_, cltt_, + subnet_id_, fqdn_fwd_, + fqdn_rev_, hostname_)); result->state_ = state; @@ -605,18 +608,16 @@ public: } private: + /// @brief Lease4 object currently being sent to the database. /// Storing this value ensures that it remains in scope while any bindings /// that refer to its contents are in use. Lease4Ptr lease_; /// @brief Lease4 specific members for binding and conversion. - uint32_t addr4_; - size_t hwaddr_length_; - std::vector hwaddr_; - uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; - size_t client_id_length_; - uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; + uint32_t addr4_; + size_t client_id_length_; + uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; }; /// @brief Supports exchanging IPv6 leases with PostgreSQL. @@ -676,9 +677,11 @@ public: }; PgSqlLease6Exchange() - : lease_(), duid_length_(0), duid_(), iaid_u_(0), iaid_str_(""), - lease_type_(Lease6::TYPE_NA), lease_type_str_(""), prefix_len_(0), - prefix_len_str_(""), pref_lifetime_(0), preferred_lifetime_str_("") { + : lease_(), duid_length_(0), duid_(duid_length_), iaid_u_(0), + iaid_str_(""), lease_type_(Lease6::TYPE_NA), lease_type_str_(""), + prefix_len_(0), prefix_len_str_(""), pref_lifetime_(0), + preferred_lifetime_str_(""), hwtype_(0), hwtype_str_(""), + hwaddr_source_(0), hwaddr_source_str_("") { BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS); @@ -761,8 +764,7 @@ public: iaid_str_ = iaid_u_.dbInputString(); bind_array.add(iaid_str_); - prefix_len_str_ = boost::lexical_cast - (static_cast(lease_->prefixlen_)); + prefix_len_str_ = boost::lexical_cast(static_cast(lease_->prefixlen_)); bind_array.add(prefix_len_str_); bind_array.add(lease->fqdn_fwd_); @@ -786,15 +788,12 @@ public: } if (lease->hwaddr_) { - hwtype_str_ = boost::lexical_cast - (static_cast(lease_->hwaddr_->htype_)); + hwtype_str_ = boost::lexical_cast(static_cast(lease_->hwaddr_->htype_)); hwaddr_source_str_ = boost::lexical_cast (static_cast(lease_->hwaddr_->source_)); } else { - hwtype_str_ = boost::lexical_cast - (static_cast(HTYPE_UNDEFINED)); - hwaddr_source_str_ = boost::lexical_cast - (static_cast(HWAddr::HWADDR_SOURCE_UNKNOWN)); + hwtype_str_ = boost::lexical_cast(static_cast(HTYPE_UNDEFINED)); + hwaddr_source_str_ = boost::lexical_cast(static_cast(HWAddr::HWADDR_SOURCE_UNKNOWN)); } bind_array.add(hwtype_str_); @@ -811,7 +810,6 @@ public: user_context_ = ""; } bind_array.add(user_context_); - } catch (const std::exception& ex) { isc_throw(DbOperationError, "Could not create bind array from Lease6: " @@ -900,12 +898,16 @@ public: } } - Lease6Ptr result(new Lease6(lease_type_, addr, duid_ptr, - iaid_u_.uval_, pref_lifetime_, - valid_lifetime_, - subnet_id_, fqdn_fwd_, fqdn_rev_, - hostname_, hwaddr, prefix_len_)); + Lease6Ptr result(boost::make_shared(lease_type_, addr, + duid_ptr, + iaid_u_.uval_, + pref_lifetime_, + valid_lifetime_, + subnet_id_, fqdn_fwd_, + fqdn_rev_, hostname_, + hwaddr, prefix_len_)); result->cltt_ = cltt_; + result->old_cltt_ = cltt_; result->state_ = state; @@ -958,24 +960,21 @@ private: /// @brief Lease6 specific members for binding and conversion. //@{ - size_t duid_length_; - vector duid_; - uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; - union Uiaid iaid_u_; - std::string iaid_str_; - Lease6::Type lease_type_; - std::string lease_type_str_; - uint8_t prefix_len_; - std::string prefix_len_str_; - uint32_t pref_lifetime_; - std::string preferred_lifetime_str_; - size_t hwaddr_length_; - vector hwaddr_; - uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; - uint32_t hwtype_; - std::string hwtype_str_; - uint32_t hwaddr_source_; - std::string hwaddr_source_str_; + size_t duid_length_; + std::vector duid_; + uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; + union Uiaid iaid_u_; + std::string iaid_str_; + Lease6::Type lease_type_; + std::string lease_type_str_; + uint8_t prefix_len_; + std::string prefix_len_str_; + uint32_t pref_lifetime_; + std::string preferred_lifetime_str_; + uint32_t hwtype_; + std::string hwtype_str_; + uint32_t hwaddr_source_; + std::string hwaddr_source_str_; //@} }; @@ -986,6 +985,7 @@ private: /// class PgSqlLeaseStatsQuery : public LeaseStatsQuery { public: + /// @brief Constructor to query for all subnets' stats /// /// The query created will return statistics for all subnets @@ -1060,7 +1060,7 @@ public: // Add last_subnet_id for range. if (getSelectMode() == SUBNET_RANGE) { // Add last_subnet_id used by range. - string subnet_id_str = boost::lexical_cast(getLastSubnetID()); + std::string subnet_id_str = boost::lexical_cast(getLastSubnetID()); parms.add(subnet_id_str); } @@ -1123,6 +1123,7 @@ public: } protected: + /// @brief Database connection to use to execute the query PgSqlConnection& conn_; @@ -1179,7 +1180,7 @@ PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() { // PgSqlLeaseMgr Constructor and Destructor PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters) - : LeaseMgr(), parameters_(parameters) { + : parameters_(parameters) { // Validate schema version first. std::pair code_version(PG_SCHEMA_VERSION_MAJOR, @@ -1276,7 +1277,12 @@ PgSqlLeaseMgr::addLease(const Lease4Ptr& lease) { PsqlBindArray bind_array; ctx->exchange4_->createBindForSend(lease, bind_array); - return (addLeaseCommon(ctx, INSERT_LEASE4, bind_array)); + auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + + return (result); } bool @@ -1292,16 +1298,22 @@ PgSqlLeaseMgr::addLease(const Lease6Ptr& lease) { PsqlBindArray bind_array; ctx->exchange6_->createBindForSend(lease, bind_array); - return (addLeaseCommon(ctx, INSERT_LEASE6, bind_array)); + auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; + + return (result); } template -void PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr ctx, - StatementIndex stindex, - PsqlBindArray& bind_array, - Exchange& exchange, - LeaseCollection& result, - bool single) const { +void +PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr ctx, + StatementIndex stindex, + PsqlBindArray& bind_array, + Exchange& exchange, + LeaseCollection& result, + bool single) const { const int n = tagged_statements[stindex].nbparams; PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name, n, @@ -1374,8 +1386,7 @@ PgSqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { PsqlBindArray bind_array; // LEASE ADDRESS - std::string addr_str = boost::lexical_cast - (addr.toUint32()); + std::string addr_str = boost::lexical_cast(addr.toUint32()); bind_array.add(addr_str); // Get the data @@ -1593,8 +1604,7 @@ PgSqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address, PsqlBindArray bind_array; // Bind lower bound address - std::string lb_address_data = boost::lexical_cast - (lower_bound_address.toUint32()); + std::string lb_address_data = boost::lexical_cast(lower_bound_address.toUint32()); bind_array.add(lb_address_data); // Bind page size value @@ -1866,8 +1876,8 @@ PgSqlLeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases, template void PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, - const size_t max_leases, - StatementIndex statement_index) const { + const size_t max_leases, + StatementIndex statement_index) const { PsqlBindArray bind_array; // Exclude reclaimed leases. @@ -1923,7 +1933,7 @@ PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr ctx, // Should not happen - primary key constraint should only have selected // one row. isc_throw(DbOperationError, "apparently updated more than one lease " - "that had the address " << lease->addr_.toText()); + "that had the address " << lease->addr_.toText()); } void @@ -1945,8 +1955,15 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { std::string addr4_str = boost::lexical_cast(lease->addr_.toUint32()); bind_array.add(addr4_str); + std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->old_cltt_, + lease->old_valid_lft_); + bind_array.add(expire_str); + // Drop to common update code updateLeaseCommon(ctx, stindex, bind_array, lease); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } void @@ -1969,8 +1986,15 @@ PgSqlLeaseMgr::updateLease6(const Lease6Ptr& lease) { std::string addr_str = lease->addr_.toText(); bind_array.add(addr_str); + std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->old_cltt_, + lease->old_valid_lft_); + bind_array.add(expire_str); + // Drop to common update code updateLeaseCommon(ctx, stindex, bind_array, lease); + + lease->old_cltt_ = lease->cltt_; + lease->old_valid_lft_ = lease->valid_lft_; } uint64_t @@ -2003,6 +2027,11 @@ PgSqlLeaseMgr::deleteLease(const Lease4Ptr& lease) { std::string addr4_str = boost::lexical_cast(addr.toUint32()); bind_array.add(addr4_str); + + std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->old_cltt_, + lease->old_valid_lft_); + bind_array.add(expire_str); + return (deleteLeaseCommon(DELETE_LEASE4, bind_array) > 0); } @@ -2018,6 +2047,11 @@ PgSqlLeaseMgr::deleteLease(const Lease6Ptr& lease) { std::string addr6_str = addr.toText(); bind_array.add(addr6_str); + + std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->old_cltt_, + lease->old_valid_lft_); + bind_array.add(expire_str); + return (deleteLeaseCommon(DELETE_LEASE6, bind_array) > 0); } @@ -2045,8 +2079,7 @@ PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs, bind_array.add(state_str); // Expiration timestamp. - std::string expiration_str = - PgSqlLeaseExchange::convertToDatabaseTime(time(NULL) - static_cast(secs)); + std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(NULL) - static_cast(secs)); bind_array.add(expiration_str); // Delete leases. diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index 5a7489e870..834584612c 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -642,6 +642,7 @@ public: }; private: + /// @brief Add Lease Common Code /// /// This method performs the common actions for both flavours (V4 and V6) @@ -857,6 +858,7 @@ private: PgSqlLeaseContextPtr ctx_; private: + /// @brief The manager const PgSqlLeaseMgr& mgr_; }; diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc index 4f1231928a..681ff966b0 100644 --- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc @@ -1923,13 +1923,13 @@ GenericLeaseMgrTest::testRecreateLease4() { Lease4Ptr lease(new Lease4(*leases[0])); // Add a lease. - EXPECT_TRUE(lmptr_->addLease(lease)); + EXPECT_TRUE(lmptr_->addLease(leases[0])); lmptr_->commit(); // Check that the lease has been successfully added. Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[0]); ASSERT_TRUE(l_returned); - detailCompareLease(lease, l_returned); + detailCompareLease(leases[0], l_returned); // Delete a lease, check that it's gone. EXPECT_TRUE(lmptr_->deleteLease(leases[0])); @@ -1963,13 +1963,13 @@ GenericLeaseMgrTest::testRecreateLease6() { Lease6Ptr lease(new Lease6(*leases[0])); // Add a lease. - EXPECT_TRUE(lmptr_->addLease(lease)); + EXPECT_TRUE(lmptr_->addLease(leases[0])); lmptr_->commit(); // Check that the lease has been successfully added. Lease6Ptr l_returned = lmptr_->getLease6(Lease::TYPE_NA, ioaddress6_[0]); ASSERT_TRUE(l_returned); - detailCompareLease(lease, l_returned); + detailCompareLease(leases[0], l_returned); // Delete a lease, check that it's gone. EXPECT_TRUE(lmptr_->deleteLease(leases[0]));