From ac229425d1aff8215e6427ed7514e6c29b74d3b4 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Wed, 24 May 2023 15:04:49 +0300 Subject: [PATCH] [#145] backend support for pool counters --- src/hooks/dhcp/stat_cmds/stat_cmds.cc | 6 + src/lib/dhcpsrv/alloc_engine.cc | 111 ++++--- src/lib/dhcpsrv/lease.cc | 70 +---- src/lib/dhcpsrv/lease.h | 18 +- src/lib/dhcpsrv/lease_mgr.cc | 103 ++++++- src/lib/dhcpsrv/lease_mgr.h | 69 ++++- src/lib/dhcpsrv/memfile_lease_mgr.cc | 391 +++++++++++++++++++++++- src/lib/dhcpsrv/memfile_lease_mgr.h | 26 ++ src/lib/dhcpsrv/mysql_lease_mgr.cc | 88 +++++- src/lib/dhcpsrv/mysql_lease_mgr.h | 28 ++ src/lib/dhcpsrv/pgsql_lease_mgr.cc | 149 ++++++--- src/lib/dhcpsrv/pgsql_lease_mgr.h | 28 ++ src/lib/dhcpsrv/tests/lease_unittest.cc | 112 ------- src/lib/dhcpsrv/tracking_lease_mgr.cc | 1 - src/lib/dhcpsrv/tracking_lease_mgr.h | 1 - 15 files changed, 860 insertions(+), 341 deletions(-) diff --git a/src/hooks/dhcp/stat_cmds/stat_cmds.cc b/src/hooks/dhcp/stat_cmds/stat_cmds.cc index eb43ae771b..4697611419 100644 --- a/src/hooks/dhcp/stat_cmds/stat_cmds.cc +++ b/src/hooks/dhcp/stat_cmds/stat_cmds.cc @@ -78,6 +78,8 @@ public: os << "[subnets " << first_subnet_id_ << " through " << last_subnet_id_ << "]"; break; + default: + os << "unsupported"; } return (os.str()); @@ -450,6 +452,8 @@ LeaseStatCmdsImpl::makeResultSet4(const ElementPtr& result_wrapper, .startSubnetRangeLeaseStatsQuery4(params.first_subnet_id_, params.last_subnet_id_); break; + default: + return (0); } // Create the result-set map. @@ -579,6 +583,8 @@ LeaseStatCmdsImpl::makeResultSet6(const ElementPtr& result_wrapper, .startSubnetRangeLeaseStatsQuery6(params.first_subnet_id_, params.last_subnet_id_); break; + default: + return (0); } // Create the result-set map. diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index ef2e7c06f9..e98edf8c35 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -1796,6 +1796,11 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx, // Add(update) the extended information on the lease. updateLease6ExtendedInfo(expired, ctx); + const auto& pool = ctx.subnet_->getPool(ctx.currentIA().type_, expired->addr_, false); + if (pool) { + expired->pool_id_ = pool->getID(); + } + // for REQUEST we do update the lease LeaseMgrFactory::instance().updateLease6(expired); @@ -1814,7 +1819,6 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx, "cumulative-assigned-nas" : "cumulative-assigned-pds"), static_cast(1)); - const auto& pool = ctx.subnet_->getPool(ctx.currentIA().type_,expired->addr_, false); if (pool) { StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), @@ -1985,6 +1989,11 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, // Add(update) the extended information on the lease. updateLease6ExtendedInfo(lease, ctx); + const auto& pool = ctx.subnet_->getPool(ctx.currentIA().type_, lease->addr_, false); + if (pool) { + lease->pool_id_ = pool->getID(); + } + // That is a real (REQUEST) allocation bool status = LeaseMgrFactory::instance().addLease(lease); @@ -2004,7 +2013,6 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, "cumulative-assigned-nas" : "cumulative-assigned-pds"), static_cast(1)); - const auto& pool = ctx.subnet_->getPool(ctx.currentIA().type_, lease->addr_, false); if (pool) { StatsMgr::instance().addValue( StatsMgr::generateName("subnet", ctx.subnet_->getID(), @@ -2332,6 +2340,10 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { // Now that the lease has been reclaimed, we can go ahead and update it // in the lease database. if (lease->reuseable_valid_lft_ == 0) { + const auto& pool = ctx.subnet_->getPool(ctx.currentIA().type_, lease->addr_, false); + if (pool) { + lease->pool_id_ = pool->getID(); + } LeaseMgrFactory::instance().updateLease6(lease); } @@ -4210,7 +4222,7 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, } // Get the context appropriate lifetime. - uint32_t valid_lft = (ctx.offer_lft_ ? ctx.offer_lft_ : getValidLft(ctx)); + uint32_t valid_lft = (ctx.offer_lft_ ? ctx.offer_lft_ : getValidLft(ctx)); time_t now = time(NULL); @@ -4290,6 +4302,10 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, } if (!ctx.fake_allocation_ || ctx.offer_lft_) { + const auto& pool = ctx.subnet_->getPool(Lease::TYPE_V4, lease->addr_, false); + if (pool) { + lease->pool_id_ = pool->getID(); + } // That is a real (REQUEST) allocation bool status = LeaseMgrFactory::instance().addLease(lease); if (status) { @@ -4305,22 +4321,18 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, "cumulative-assigned-addresses"), static_cast(1)); - const auto& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(ctx.subnet_->getID()); - if (subnet) { - const auto& pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false); - if (pool) { - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "assigned-addresses")), - static_cast(1)); + if (pool) { + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "assigned-addresses")), + static_cast(1)); - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "cumulative-assigned-addresses")), - static_cast(1)); - } + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "cumulative-assigned-addresses")), + static_cast(1)); } StatsMgr::instance().addValue("cumulative-assigned-addresses", @@ -4363,7 +4375,7 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, setLeaseReusable(lease, ctx); } - if (!ctx.fake_allocation_ || ctx.offer_lft_) { + if (!ctx.fake_allocation_ || ctx.offer_lft_) { // If the lease is expired we have to reclaim it before // re-assigning it to the client. The lease reclamation // involves execution of hooks and DNS update. @@ -4424,6 +4436,11 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, } if ((!ctx.fake_allocation_ || ctx.offer_lft_) && !skip && (lease->reuseable_valid_lft_ == 0)) { + const auto& pool = ctx.subnet_->getPool(Lease::TYPE_V4, lease->addr_, false); + if (pool) { + lease->pool_id_ = pool->getID(); + } + // for REQUEST we do update the lease LeaseMgrFactory::instance().updateLease4(lease); @@ -4439,22 +4456,18 @@ AllocEngine::renewLease4(const Lease4Ptr& lease, "cumulative-assigned-addresses"), static_cast(1)); - const auto& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(ctx.subnet_->getID()); - if (subnet) { - const auto& pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false); - if (pool) { - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "assigned-addresses")), - static_cast(1)); + if (pool) { + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "assigned-addresses")), + static_cast(1)); - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "cumulative-assigned-addresses")), - static_cast(1)); - } + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "cumulative-assigned-addresses")), + static_cast(1)); } StatsMgr::instance().addValue("cumulative-assigned-addresses", @@ -4551,6 +4564,10 @@ AllocEngine::reuseExpiredLease4(Lease4Ptr& expired, } if (!ctx.fake_allocation_ || ctx.offer_lft_) { + const auto& pool = ctx.subnet_->getPool(Lease::TYPE_V4, expired->addr_, false); + if (pool) { + expired->pool_id_ = pool->getID(); + } // for REQUEST we do update the lease LeaseMgrFactory::instance().updateLease4(expired); @@ -4565,22 +4582,18 @@ AllocEngine::reuseExpiredLease4(Lease4Ptr& expired, "cumulative-assigned-addresses"), static_cast(1)); - const auto& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(ctx.subnet_->getID()); - if (subnet) { - const auto& pool = subnet->getPool(Lease::TYPE_V4, expired->addr_, false); - if (pool) { - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "assigned-addresses")), - static_cast(1)); + if (pool) { + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "assigned-addresses")), + static_cast(1)); - StatsMgr::instance().addValue( - StatsMgr::generateName("subnet", subnet->getID(), - StatsMgr::generateName(".pool", pool->getID(), - "cumulative-assigned-addresses")), - static_cast(1)); - } + StatsMgr::instance().addValue( + StatsMgr::generateName("subnet", ctx.subnet_->getID(), + StatsMgr::generateName(".pool", pool->getID(), + "cumulative-assigned-addresses")), + static_cast(1)); } StatsMgr::instance().addValue("cumulative-assigned-addresses", diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc index debc08a81b..d750c14faf 100644 --- a/src/lib/dhcpsrv/lease.cc +++ b/src/lib/dhcpsrv/lease.cc @@ -309,34 +309,6 @@ Lease::syncCurrentExpirationTime(const Lease& from, Lease& to) { to.current_valid_lft_ = from.valid_lft_; } -Lease4::Lease4(const Lease4& other) - : Lease(other.addr_, other.valid_lft_, - other.subnet_id_, other.cltt_, other.fqdn_fwd_, - other.fqdn_rev_, other.hostname_, other.hwaddr_) { - - // Copy over fields derived from Lease. - state_ = other.state_; - - // Copy the hardware address if it is defined. - if (other.hwaddr_) { - hwaddr_.reset(new HWAddr(*other.hwaddr_)); - } else { - hwaddr_.reset(); - } - - if (other.client_id_) { - client_id_.reset(new ClientId(other.client_id_->getClientId())); - } else { - client_id_.reset(); - } - - if (other.getContext()) { - setContext(other.getContext()); - relay_id_ = other.relay_id_; - remote_id_ = other.remote_id_; - } -} - Lease4::Lease4(const isc::asiolink::IOAddress& address, const HWAddrPtr& hw_address, const ClientIdPtr& client_id, @@ -346,12 +318,14 @@ Lease4::Lease4(const isc::asiolink::IOAddress& address, const bool fqdn_fwd, const bool fqdn_rev, const std::string& hostname) - : Lease(address, valid_lifetime, subnet_id, cltt, fqdn_fwd, fqdn_rev, hostname, hw_address), client_id_(client_id), remote_id_(), relay_id_() { } +Lease4::Lease4() : Lease(0, 0, 0, 0, false, false, "", HWAddrPtr()) { +} + std::string Lease4::statesToText(const uint32_t state) { return (Lease::basicStatesToText(state)); @@ -405,44 +379,6 @@ Lease4::decline(uint32_t probation_period) { valid_lft_ = probation_period; } -Lease4& -Lease4::operator=(const Lease4& other) { - if (this != &other) { - addr_ = other.addr_; - valid_lft_ = other.valid_lft_; - current_valid_lft_ = other.current_valid_lft_; - reuseable_valid_lft_ = other.reuseable_valid_lft_; - cltt_ = other.cltt_; - current_cltt_ = other.current_cltt_; - subnet_id_ = other.subnet_id_; - pool_id_ = other.pool_id_; - hostname_ = other.hostname_; - fqdn_fwd_ = other.fqdn_fwd_; - fqdn_rev_ = other.fqdn_rev_; - state_ = other.state_; - - // Copy the hardware address if it is defined. - if (other.hwaddr_) { - hwaddr_.reset(new HWAddr(*other.hwaddr_)); - } else { - hwaddr_.reset(); - } - - if (other.client_id_) { - client_id_.reset(new ClientId(other.client_id_->getClientId())); - } else { - client_id_.reset(); - } - - if (other.getContext()) { - setContext(other.getContext()); - relay_id_ = other.relay_id_; - remote_id_ = other.remote_id_; - } - } - return (*this); -} - isc::data::ElementPtr Lease4::toElement() const { // Prepare the map diff --git a/src/lib/dhcpsrv/lease.h b/src/lib/dhcpsrv/lease.h index 733d1974a6..f84302d276 100644 --- a/src/lib/dhcpsrv/lease.h +++ b/src/lib/dhcpsrv/lease.h @@ -354,14 +354,7 @@ struct Lease4 : public Lease { /// @brief Default constructor /// /// Initialize fields that don't have a default constructor. - Lease4() : Lease(0, 0, 0, 0, false, false, "", HWAddrPtr()) - { - } - - /// @brief Copy constructor - /// - /// @param other the @c Lease4 object to be copied. - Lease4(const Lease4& other); + Lease4(); /// @brief Returns Lease type /// @@ -457,11 +450,6 @@ struct Lease4 : public Lease { bool belongsToClient(const HWAddrPtr& hw_address, const ClientIdPtr& client_id) const; - /// @brief Assignment operator. - /// - /// @param other the @c Lease4 object to be assigned. - Lease4& operator=(const Lease4& other); - /// @brief Compare two leases for equality /// /// @param other lease6 object with which to compare @@ -719,7 +707,7 @@ template using LeaseTPtr = boost::shared_ptr>; /// @} -}; // end of isc::dhcp namespace -}; // end of isc namespace +} // end of isc::dhcp namespace +} // end of isc namespace #endif // LEASE_H diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc index b3109f7f5a..55d370b6d7 100644 --- a/src/lib/dhcpsrv/lease_mgr.cc +++ b/src/lib/dhcpsrv/lease_mgr.cc @@ -197,12 +197,44 @@ LeaseMgr::recountLeaseStats4() { row.state_count_); } } - // Can not update counters at pool level. This would require retrieving all - // leases and matching them one by one to one possible pool. + + query = startPoolLeaseStatsQuery4(); + if (!query) { + /// NULL means not backend does not support recounting. + return; + } + + // Get counts per state per subnet and pool. Iterate over the result set + // updating the subnet and pool and global values. + while (query->getNextRow(row)) { + if (row.lease_state_ == Lease::STATE_DEFAULT) { + // Add to subnet and pool level value. + stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "assigned-addresses")), + row.state_count_); + } else if (row.lease_state_ == Lease::STATE_DECLINED) { + // Set subnet and pool level value. + stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "declined-addresses")), + row.state_count_); + + // Add to subnet and pool level value. + // Declined leases also count as assigned. + stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "assigned-addresses")), + row.state_count_); + } + } } -LeaseStatsQuery::LeaseStatsQuery() - : first_subnet_id_(0), last_subnet_id_(0), select_mode_(ALL_SUBNETS) { +LeaseStatsQuery::LeaseStatsQuery(const SelectMode& select_mode) + : first_subnet_id_(0), last_subnet_id_(0), select_mode_(select_mode) { + if (select_mode != ALL_SUBNETS && select_mode != ALL_SUBNET_POOLS) { + isc_throw(BadValue, "LeaseStatsQuery: mode must be either ALL_SUBNETS or ALL_SUBNET_POOLS"); + } } LeaseStatsQuery::LeaseStatsQuery(const SubnetID& subnet_id) @@ -238,6 +270,11 @@ LeaseMgr::startLeaseStatsQuery4() { return(LeaseStatsQueryPtr()); } +LeaseStatsQueryPtr +LeaseMgr::startPoolLeaseStatsQuery4() { + return(LeaseStatsQueryPtr()); +} + LeaseStatsQueryPtr LeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& /* subnet_id */) { return(LeaseStatsQueryPtr()); @@ -419,12 +456,59 @@ LeaseMgr::recountLeaseStats6() { break; default: - // We dont' support TYPE_TAs yet + // We don't support TYPE_TAs yet + break; + } + } + + query = startPoolLeaseStatsQuery6(); + if (!query) { + /// NULL means not backend does not support recounting. + return; + } + + // Get counts per state per subnet and pool. Iterate over the result set + // updating the subnet and pool and global values. + while (query->getNextRow(row)) { + switch(row.lease_type_) { + case Lease::TYPE_NA: + if (row.lease_state_ == Lease::STATE_DEFAULT) { + // Add to subnet and pool level value. + stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "assigned-nas")), + row.state_count_); + } else if (row.lease_state_ == Lease::STATE_DECLINED) { + // Set subnet and pool level value. + stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "declined-addresses")), + row.state_count_); + + // Add to subnet and pool level value. + // Declined leases also count as assigned. + stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pool", row.pool_id_, + "assigned-nas")), + row.state_count_); + } + break; + + case Lease::TYPE_PD: + if (row.lease_state_ == Lease::STATE_DEFAULT) { + // Set subnet and pool level value. + stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_, + StatsMgr::generateName(".pd-pool", row.pool_id_, + "assigned-pds")), + row.state_count_); + } + break; + + default: + // We don't support TYPE_TAs yet break; } } - // Can not update counters at pool level. This would require retrieving all - // leases and matching them one by one to one possible pool. } LeaseStatsQueryPtr @@ -432,6 +516,11 @@ LeaseMgr::startLeaseStatsQuery6() { return(LeaseStatsQueryPtr()); } +LeaseStatsQueryPtr +LeaseMgr::startPoolLeaseStatsQuery6() { + return(LeaseStatsQueryPtr()); +} + LeaseStatsQueryPtr LeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& /* subnet_id */) { return(LeaseStatsQueryPtr()); diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 50277f0996..a1259e54d6 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -64,7 +64,7 @@ public: struct LeaseStatsRow { /// @brief Default constructor LeaseStatsRow() : - subnet_id_(0), lease_type_(Lease::TYPE_NA), + subnet_id_(0), pool_id_(0), lease_type_(Lease::TYPE_NA), lease_state_(Lease::STATE_DEFAULT), state_count_(0) { } @@ -75,9 +75,11 @@ struct LeaseStatsRow { /// @param subnet_id The subnet id to which this data applies /// @param lease_state The lease state counted /// @param state_count The count of leases in the lease state + /// @param pool_id The pool id to which this data applies or 0 if it is not + /// used LeaseStatsRow(const SubnetID& subnet_id, const uint32_t lease_state, - const int64_t state_count) - : subnet_id_(subnet_id), lease_type_(Lease::TYPE_NA), + const int64_t state_count, uint32_t pool_id = 0) + : subnet_id_(subnet_id), pool_id_(pool_id), lease_type_(Lease::TYPE_NA), lease_state_(lease_state), state_count_(state_count) { } @@ -87,9 +89,12 @@ struct LeaseStatsRow { /// @param lease_type The lease type for this state count /// @param lease_state The lease state counted /// @param state_count The count of leases in the lease state + /// @param pool_id The pool id to which this data applies or 0 if it is not + /// used LeaseStatsRow(const SubnetID& subnet_id, const Lease::Type& lease_type, - const uint32_t lease_state, const int64_t state_count) - : subnet_id_(subnet_id), lease_type_(lease_type), + const uint32_t lease_state, const int64_t state_count, + uint32_t pool_id = 0) + : subnet_id_(subnet_id), pool_id_(pool_id), lease_type_(lease_type), lease_state_(lease_state), state_count_(state_count) { } @@ -100,14 +105,21 @@ struct LeaseStatsRow { } if (subnet_id_ == rhs.subnet_id_ && + pool_id_ < rhs.pool_id_) { + return (true); + } + + if (subnet_id_ == rhs.subnet_id_ && + pool_id_ == rhs.pool_id_ && lease_type_ < rhs.lease_type_) { - return (true); + return (true); } if (subnet_id_ == rhs.subnet_id_ && + pool_id_ == rhs.pool_id_ && lease_type_ == rhs.lease_type_ && lease_state_ < rhs.lease_state_) { - return (true); + return (true); } return (false); @@ -115,10 +127,16 @@ struct LeaseStatsRow { /// @brief The subnet ID to which this data applies SubnetID subnet_id_; + + /// @brief The pool ID to which this data applies + uint32_t pool_id_; + /// @brief The lease_type to which the count applies Lease::Type lease_type_; + /// @brief The lease_state to which the count applies uint32_t lease_state_; + /// @brief state_count The count of leases in the lease state int64_t state_count_; }; @@ -134,12 +152,17 @@ public: typedef enum { ALL_SUBNETS, SINGLE_SUBNET, - SUBNET_RANGE + SUBNET_RANGE, + ALL_SUBNET_POOLS } SelectMode; - /// @brief Default constructor + /// @brief Constructor to query statistics for all subnets + /// /// The query created will return statistics for all subnets - LeaseStatsQuery(); + /// + /// @param select_mode The selection criteria which is either ALL_SUBNETS or + /// ALL_SUBNET_POOLS + LeaseStatsQuery(const SelectMode& select_mode = ALL_SUBNETS); /// @brief Constructor to query for a single subnet's stats /// @@ -600,6 +623,19 @@ public: /// @return A populated LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery4(); + /// @brief Creates and runs the IPv4 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv4 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4(); + /// @brief Creates and runs the IPv4 lease stats query for a single subnet /// /// LeaseMgr derivations implement this method such that it creates and @@ -657,6 +693,19 @@ public: /// @return A populated LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery6(); + /// @brief Creates and runs the IPv6 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv6 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6(); + /// @brief Creates and runs the IPv6 lease stats query for a single subnet /// /// LeaseMgr derivations implement this method such that it creates and diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index d86b7025c9..62ac6c4f1c 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -266,8 +266,10 @@ class MemfileLeaseStatsQuery : public LeaseStatsQuery { public: /// @brief Constructor for all subnets query /// - MemfileLeaseStatsQuery() - : rows_(0), next_pos_(rows_.end()) { + /// @param select_mode The selection criteria which is either ALL_SUBNETS or + /// ALL_SUBNET_POOLS + MemfileLeaseStatsQuery(const SelectMode& select_mode = ALL_SUBNETS) + : LeaseStatsQuery(select_mode), rows_(0), next_pos_(rows_.end()) { }; /// @brief Constructor for single subnet query @@ -335,8 +337,11 @@ public: /// @brief Constructor for an all subnets query /// /// @param storage4 A pointer to the v4 lease storage to be counted - MemfileLeaseStatsQuery4(Lease4Storage& storage4) - : MemfileLeaseStatsQuery(), storage4_(storage4) { + /// @param select_mode The selection criteria which is either ALL_SUBNETS or + /// ALL_SUBNET_POOLS + MemfileLeaseStatsQuery4(Lease4Storage& storage4, + const SelectMode& select_mode = ALL_SUBNETS) + : MemfileLeaseStatsQuery(select_mode), storage4_(storage4) { }; /// @brief Constructor for a single subnet query @@ -363,7 +368,35 @@ public: /// @brief Creates the IPv4 lease statistical data result set /// /// The result set is populated by iterating over the IPv4 leases in - /// storage, in ascending order by address, accumulating the lease state + /// storage, in ascending order by subnet id or by subnet id and pool id, + /// accumulating the lease state counts per subnet or per subnet and pool. + /// At the completion of all entries for a given subnet or pool, the counts + /// are used to create LeaseStatsRow instances which are appended to an + /// internal vector. The process results in a vector containing one entry + /// per state per subnet or per subnet and pool. + /// + /// Currently the states counted are: + /// + /// - Lease::STATE_DEFAULT (i.e. assigned) + /// - Lease::STATE_DECLINED + void start() { + switch (getSelectMode()) { + case ALL_SUBNETS: + case SINGLE_SUBNET: + case SUBNET_RANGE: + startSubnets(); + break; + + case ALL_SUBNET_POOLS: + startSubnetPools(); + break; + } + } + + /// @brief Creates the IPv4 lease statistical data result set + /// + /// The result set is populated by iterating over the IPv4 leases in + /// storage, in ascending order by subnet id, accumulating the lease state /// counts per subnet. /// At the completion of all entries for a given subnet, the counts are /// used to create LeaseStatsRow instances which are appended to an @@ -374,13 +407,14 @@ public: /// /// - Lease::STATE_DEFAULT (i.e. assigned) /// - Lease::STATE_DECLINED - void start() { + void startSubnets() { const Lease4StorageSubnetIdIndex& idx = storage4_.get(); // Set lower and upper bounds based on select mode Lease4StorageSubnetIdIndex::const_iterator lower; Lease4StorageSubnetIdIndex::const_iterator upper; + switch (getSelectMode()) { case ALL_SUBNETS: lower = idx.begin(); @@ -396,6 +430,9 @@ public: lower = idx.lower_bound(getFirstSubnetID()); upper = idx.upper_bound(getLastSubnetID()); break; + + default: + return; } // Return an empty set if there are no rows. @@ -457,6 +494,122 @@ public: next_pos_ = rows_.begin(); } + /// @brief Creates the IPv4 lease statistical data result set + /// + /// The result set is populated by iterating over the IPv4 leases in + /// storage, in ascending order by subnet id and pool id, accumulating the + /// lease state counts per subnet and pool. + /// At the completion of all entries for a given subnet or pool, the counts + /// are used to create LeaseStatsRow instances which are appended to an + /// internal vector. The process results in a vector containing one entry + /// per state per subnet and pool. + /// + /// Currently the states counted are: + /// + /// - Lease::STATE_DEFAULT (i.e. assigned) + /// - Lease::STATE_DECLINED + void startSubnetPools() { + const Lease4StorageSubnetIdPoolIdIndex& idx + = storage4_.get(); + + // Set lower and upper bounds based on select mode + Lease4StorageSubnetIdPoolIdIndex::const_iterator lower; + Lease4StorageSubnetIdPoolIdIndex::const_iterator upper; + + switch (getSelectMode()) { + case ALL_SUBNET_POOLS: + lower = idx.begin(); + upper = idx.end(); + break; + + default: + return; + } + + // Return an empty set if there are no rows. + if (lower == upper) { + return; + } + + // Iterate over the leases in order by subnet and pool, accumulating per + // subnet and pool counts for each state of interest. As we finish each + // subnet or pool, add the appropriate rows to our result set. + SubnetID cur_id = 0; + uint32_t cur_pool_id = 0; + int64_t assigned = 0; + int64_t declined = 0; + for (Lease4StorageSubnetIdPoolIdIndex::const_iterator lease = lower; + lease != upper; ++lease) { + // If we've hit the next pool, add rows for the current subnet and + // pool and wipe the accumulators + if ((*lease)->pool_id_ != cur_pool_id) { + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, + Lease::STATE_DEFAULT, + assigned, cur_pool_id)); + assigned = 0; + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, + Lease::STATE_DECLINED, + declined, cur_pool_id)); + declined = 0; + } + + // Update current pool id + cur_pool_id = (*lease)->pool_id_; + } + + // If we've hit the next subnet, add rows for the current subnet + // and wipe the accumulators + if ((*lease)->subnet_id_ != cur_id) { + if (cur_id > 0) { + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, + Lease::STATE_DEFAULT, + assigned, cur_pool_id)); + assigned = 0; + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, + Lease::STATE_DECLINED, + declined, cur_pool_id)); + declined = 0; + } + } + + // Update current subnet id + cur_id = (*lease)->subnet_id_; + + // Reset pool id + cur_pool_id = 0; + } + + // Bump the appropriate accumulator + if ((*lease)->state_ == Lease::STATE_DEFAULT) { + ++assigned; + } else if ((*lease)->state_ == Lease::STATE_DECLINED) { + ++declined; + } + } + + // Make the rows for last subnet + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT, + assigned, cur_pool_id)); + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED, + declined, cur_pool_id)); + } + + // Reset the next row position back to the beginning of the rows. + next_pos_ = rows_.begin(); + } + private: /// @brief The Memfile storage containing the IPv4 leases to analyze Lease4Storage& storage4_; @@ -477,8 +630,11 @@ public: /// @brief Constructor /// /// @param storage6 A pointer to the v6 lease storage to be counted - MemfileLeaseStatsQuery6(Lease6Storage& storage6) - : MemfileLeaseStatsQuery(), storage6_(storage6) { + /// @param select_mode The selection criteria which is either ALL_SUBNETS or + /// ALL_SUBNET_POOLS + MemfileLeaseStatsQuery6(Lease6Storage& storage6, + const SelectMode& select_mode = ALL_SUBNETS) + : MemfileLeaseStatsQuery(select_mode), storage6_(storage6) { }; /// @brief Constructor for a single subnet query @@ -502,20 +658,49 @@ public: /// @brief Destructor virtual ~MemfileLeaseStatsQuery6() {}; + /// @brief Creates the IPv6 lease statistical data result set + /// + /// The result set is populated by iterating over the IPv6 leases in + /// storage, in ascending order by subnet id or by subnet id and pool id, + /// accumulating the lease state counts per subnet or per subnet and pool. + /// At the completion of all entries for a given subnet or pool, the counts + /// are used to create LeaseStatsRow instances which are appended to an + /// internal vector. The process results in a vector containing one entry + /// per state per subnet or per subnet and pool. + /// + /// Currently the states counted are: + /// + /// - Lease::STATE_DEFAULT (i.e. assigned) + /// - Lease::STATE_DECLINED + void start() { + switch (getSelectMode()) { + case ALL_SUBNETS: + case SINGLE_SUBNET: + case SUBNET_RANGE: + startSubnets(); + break; + + case ALL_SUBNET_POOLS: + startSubnetPools(); + break; + } + } + /// @brief Creates the IPv6 lease statistical data result set /// /// The result set is populated by iterating over the IPv6 leases in /// storage, in ascending order by subnet id, accumulating the lease state - /// counts per subnet. At the completion of all entries for a given subnet, - /// the counts are used to create LeaseStatsRow instances which are appended - /// to an internal vector. The process results in a vector containing one - /// entry per state per lease type per subnet. + /// counts per subnet. + /// At the completion of all entries for a given subnet, the counts are + /// used to create LeaseStatsRow instances which are appended to an + /// internal vector. The process results in a vector containing one entry + /// per state per subnet. /// /// Currently the states counted are: /// /// - Lease::STATE_DEFAULT (i.e. assigned) /// - Lease::STATE_DECLINED - virtual void start() { + virtual void startSubnets() { // Get the subnet_id index const Lease6StorageSubnetIdIndex& idx = storage6_.get(); @@ -538,6 +723,9 @@ public: lower = idx.lower_bound(getFirstSubnetID()); upper = idx.upper_bound(getLastSubnetID()); break; + + default: + return; } // Return an empty set if there are no rows. @@ -624,6 +812,157 @@ public: next_pos_ = rows_.begin(); } + /// @brief Creates the IPv6 lease statistical data result set + /// + /// The result set is populated by iterating over the IPv6 leases in + /// storage, in ascending order by subnet id and pool id, accumulating the + /// lease state counts per subnet and pool. + /// At the completion of all entries for a given subnet or pool, the counts + /// are used to create LeaseStatsRow instances which are appended to an + /// internal vector. The process results in a vector containing one entry + /// per state per subnet and pool. + /// + /// Currently the states counted are: + /// + /// - Lease::STATE_DEFAULT (i.e. assigned) + /// - Lease::STATE_DECLINED + virtual void startSubnetPools() { + // Get the subnet_id index + const Lease6StorageSubnetIdPoolIdIndex& idx + = storage6_.get(); + + // Set lower and upper bounds based on select mode + Lease6StorageSubnetIdPoolIdIndex::const_iterator lower; + Lease6StorageSubnetIdPoolIdIndex::const_iterator upper; + switch (getSelectMode()) { + case ALL_SUBNET_POOLS: + lower = idx.begin(); + upper = idx.end(); + break; + + default: + return; + } + + // Return an empty set if there are no rows. + if (lower == upper) { + return; + } + + // Iterate over the leases in order by subnet, accumulating per + // subnet counts for each state of interest. As we finish each + // subnet, add the appropriate rows to our result set. + SubnetID cur_id = 0; + uint32_t cur_pool_id = 0; + int64_t assigned = 0; + int64_t declined = 0; + int64_t assigned_pds = 0; + for (Lease6StorageSubnetIdPoolIdIndex::const_iterator lease = lower; + lease != upper; ++lease) { + // If we've hit the next pool, add rows for the current subnet and + // pool and wipe the accumulators + if ((*lease)->pool_id_ != cur_pool_id) { + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DEFAULT, + assigned, cur_pool_id)); + assigned = 0; + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DECLINED, + declined, cur_pool_id)); + declined = 0; + } + + if (assigned_pds > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD, + Lease::STATE_DEFAULT, + assigned_pds, cur_pool_id)); + assigned_pds = 0; + } + + // Update current pool id + cur_pool_id = (*lease)->pool_id_; + } + + // If we've hit the next subnet, add rows for the current subnet + // and wipe the accumulators + if ((*lease)->subnet_id_ != cur_id) { + if (cur_id > 0) { + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DEFAULT, + assigned, cur_pool_id)); + assigned = 0; + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DECLINED, + declined, cur_pool_id)); + declined = 0; + } + + if (assigned_pds > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD, + Lease::STATE_DEFAULT, + assigned_pds, cur_pool_id)); + assigned_pds = 0; + } + } + + // Update current subnet id + cur_id = (*lease)->subnet_id_; + + // Reset pool id + cur_pool_id = 0; + } + + // Bump the appropriate accumulator + if ((*lease)->state_ == Lease::STATE_DEFAULT) { + switch((*lease)->type_) { + case Lease::TYPE_NA: + ++assigned; + break; + case Lease::TYPE_PD: + ++assigned_pds; + break; + default: + break; + } + } else if ((*lease)->state_ == Lease::STATE_DECLINED) { + // In theory only NAs can be declined + if (((*lease)->type_) == Lease::TYPE_NA) { + ++declined; + } + } + } + + // Make the rows for last subnet, unless there were no rows + if (assigned > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DEFAULT, assigned, + cur_pool_id)); + } + + if (declined > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA, + Lease::STATE_DECLINED, declined, + cur_pool_id)); + } + + if (assigned_pds > 0) { + rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD, + Lease::STATE_DEFAULT, assigned_pds, + cur_pool_id)); + } + + // Set the next row position to the beginning of the rows. + next_pos_ = rows_.begin(); + } + private: /// @brief The Memfile storage containing the IPv6 leases to analyze Lease6Storage& storage6_; @@ -2097,6 +2436,19 @@ Memfile_LeaseMgr::startLeaseStatsQuery4() { return(query); } +LeaseStatsQueryPtr +Memfile_LeaseMgr::startPoolLeaseStatsQuery4() { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, LeaseStatsQuery::ALL_SUBNET_POOLS)); + if (MultiThreadingMgr::instance().getMode()) { + std::lock_guard lock(*mutex_); + query->start(); + } else { + query->start(); + } + + return(query); +} + LeaseStatsQueryPtr Memfile_LeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) { LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, subnet_id)); @@ -2138,6 +2490,19 @@ Memfile_LeaseMgr::startLeaseStatsQuery6() { return(query); } +LeaseStatsQueryPtr +Memfile_LeaseMgr::startPoolLeaseStatsQuery6() { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_, LeaseStatsQuery::ALL_SUBNET_POOLS)); + if (MultiThreadingMgr::instance().getMode()) { + std::lock_guard lock(*mutex_); + query->start(); + } else { + query->start(); + } + + return(query); +} + LeaseStatsQueryPtr Memfile_LeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) { LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_, subnet_id)); diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index 2afdb7aa2b..71ec646927 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -1115,6 +1115,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv4 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for a single subnet /// /// It creates an instance of a MemfileLeaseStatsQuery4 for a single subnet @@ -1146,6 +1159,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery. virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv6 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for a single subnet /// /// It creates an instance of a MemfileLeaseStatsQuery6 for a single subnet diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index 6506b28c06..a7dc60ea15 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -166,7 +166,7 @@ tagged_statements = { { "SELECT address, hwaddr, client_id, " "valid_lifetime, expire, subnet_id, " "fqdn_fwd, fqdn_rev, hostname, " - "state, user_context, relay_id, remote_id " + "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " "WHERE address > ? AND user_context IS NOT NULL " "ORDER BY address " @@ -345,7 +345,7 @@ tagged_statements = { { "lease_type, iaid, prefix_len, " "fqdn_fwd, fqdn_rev, hostname, " "hwaddr, hwtype, hwaddr_source, " - "state, user_context " + "state, user_context, pool_id " "FROM lease6 " "WHERE address > ? AND user_context IS NOT NULL " "ORDER BY address " @@ -456,6 +456,9 @@ tagged_statements = { { "FROM lease4_stat " "WHERE subnet_id >= ? and subnet_id <= ? " "ORDER BY subnet_id, state"}, + {MySqlLeaseMgr::ALL_POOL_LEASE4_STATS, + "SELECT subnet_id, pool_id, state, leases as state_count " + "FROM lease4_pool_stat ORDER BY subnet_id, pool_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"}, @@ -469,9 +472,15 @@ tagged_statements = { { "FROM lease6_stat " "WHERE subnet_id >= ? and subnet_id <= ? " "ORDER BY subnet_id, lease_type, state"}, - {MySqlLeaseMgr::CHECK_LEASE4_LIMITS, "SELECT checkLease4Limits(?)"}, - {MySqlLeaseMgr::CHECK_LEASE6_LIMITS, "SELECT checkLease6Limits(?)"}, - {MySqlLeaseMgr::IS_JSON_SUPPORTED, "SELECT isJsonSupported()"}, + {MySqlLeaseMgr::ALL_POOL_LEASE6_STATS, + "SELECT subnet_id, pool_id, lease_type, state, leases as state_count " + "FROM lease6_pool_stat ORDER BY subnet_id, pool_id, lease_type, state"}, + {MySqlLeaseMgr::CHECK_LEASE4_LIMITS, + "SELECT checkLease4Limits(?)"}, + {MySqlLeaseMgr::CHECK_LEASE6_LIMITS, + "SELECT checkLease6Limits(?)"}, + {MySqlLeaseMgr::IS_JSON_SUPPORTED, + "SELECT isJsonSupported()"}, {MySqlLeaseMgr::GET_LEASE4_COUNT_BY_CLASS, "SELECT leases " "FROM lease4_stat_by_client_class " @@ -1797,15 +1806,17 @@ public: /// @param conn An open connection to the database housing the lease data /// @param statement_index Index of the query's prepared statement /// @param fetch_type Indicates if query supplies lease type + /// @param fetch_pool Indicates if query requires pool data /// @throw if statement index is invalid. MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index, - const bool fetch_type) + const bool fetch_type, const bool fetch_pool = false) : conn_(conn), statement_index_(statement_index), statement_(NULL), - fetch_type_(fetch_type), + fetch_type_(fetch_type), fetch_pool_(fetch_pool), // Set the number of columns in the bind array based on fetch_type // This is the number of columns expected in the result set - bind_(fetch_type_ ? 4 : 3), - subnet_id_(0), lease_type_(0), state_(0), state_count_(0) { + bind_(fetch_type_ ? (fetch_pool_ ? 5 : 4) : (fetch_pool_ ? 4 : 3)), + subnet_id_(0), pool_id_(0), lease_type_(Lease::TYPE_NA), + state_(Lease::STATE_DEFAULT), state_count_(0) { validateStatement(); } @@ -1821,11 +1832,12 @@ public: MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index, const bool fetch_type, const SubnetID& subnet_id) : LeaseStatsQuery(subnet_id), conn_(conn), statement_index_(statement_index), - statement_(NULL), fetch_type_(fetch_type), + statement_(NULL), fetch_type_(fetch_type), fetch_pool_(false), // Set the number of columns in the bind array based on fetch_type // This is the number of columns expected in the result set - bind_(fetch_type_ ? 4 : 3), - subnet_id_(0), lease_type_(0), state_(0), state_count_(0) { + bind_(fetch_type_ ? 4 : 3), subnet_id_(0), pool_id_(0), + lease_type_(Lease::TYPE_NA), state_(Lease::STATE_DEFAULT), + state_count_(0) { validateStatement(); } @@ -1845,11 +1857,13 @@ public: const bool fetch_type, const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), - statement_index_(statement_index), statement_(NULL), fetch_type_(fetch_type), + statement_index_(statement_index), statement_(NULL), + fetch_type_(fetch_type), fetch_pool_(false), // Set the number of columns in the bind array based on fetch_type // This is the number of columns expected in the result set - bind_(fetch_type_ ? 4 : 3), - subnet_id_(0), lease_type_(0), state_(0), state_count_(0) { + bind_(fetch_type_ ? 4 : 3), subnet_id_(0), pool_id_(0), + lease_type_(Lease::TYPE_NA), state_(Lease::STATE_DEFAULT), + state_count_(0) { validateStatement(); } @@ -1867,7 +1881,7 @@ public: /// entire result set. void start() { // Set up where clause inputs if needed. - if (getSelectMode() != ALL_SUBNETS) { + if (getSelectMode() != ALL_SUBNETS && getSelectMode() != ALL_SUBNET_POOLS) { MYSQL_BIND inbind[2]; memset(inbind, 0, sizeof(inbind)); @@ -1895,6 +1909,15 @@ public: bind_[col].is_unsigned = MLM_TRUE; ++col; + // Fetch the pool id if we were told to do so. + if (fetch_pool_) { + // pool id: uint32_t + bind_[col].buffer_type = MYSQL_TYPE_LONG; + bind_[col].buffer = reinterpret_cast(&pool_id_); + bind_[col].is_unsigned = MLM_TRUE; + ++col; + } + // Fetch the lease type if we were told to do so. if (fetch_type_) { // lease type: uint32_t @@ -1952,6 +1975,7 @@ public: int status = mysql_stmt_fetch(statement_); if (status == MLM_MYSQL_FETCH_SUCCESS) { row.subnet_id_ = static_cast(subnet_id_); + row.pool_id_ = pool_id_; row.lease_type_ = static_cast(lease_type_); row.lease_state_ = state_; if (state_count_ >= 0) { @@ -1997,12 +2021,18 @@ private: /// @brief Indicates if query supplies lease type bool fetch_type_; + /// @brief Indicates if query requires pool data + bool fetch_pool_; + /// @brief Bind array used to store the query result set; std::vector bind_; /// @brief Receives subnet ID when fetching a row uint32_t subnet_id_; + /// @brief Receives pool ID when fetching a row + uint32_t pool_id_; + /// @brief Receives the lease type when fetching a row uint32_t lease_type_; @@ -3584,6 +3614,19 @@ MySqlLeaseMgr::startLeaseStatsQuery4() { return(query); } +LeaseStatsQueryPtr +MySqlLeaseMgr::startPoolLeaseStatsQuery4() { + // Get a context + MySqlLeaseContextAlloc get_context(*this); + MySqlLeaseContextPtr ctx = get_context.ctx_; + + LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_, + ALL_POOL_LEASE4_STATS, + false, true)); + query->start(); + return(query); +} + LeaseStatsQueryPtr MySqlLeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) { // Get a context @@ -3627,6 +3670,19 @@ MySqlLeaseMgr::startLeaseStatsQuery6() { return(query); } +LeaseStatsQueryPtr +MySqlLeaseMgr::startPoolLeaseStatsQuery6() { + // Get a context + MySqlLeaseContextAlloc get_context(*this); + MySqlLeaseContextPtr ctx = get_context.ctx_; + + LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_, + ALL_POOL_LEASE6_STATS, + true, true)); + query->start(); + return(query); +} + LeaseStatsQueryPtr MySqlLeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) { // Get a context diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h index 58d50a45dd..e1abd88bd2 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -562,6 +562,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv4 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for a single subnet /// /// It creates an instance of a MySqlLeaseStatsQuery4 for a single subnet @@ -594,6 +607,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv6 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for a single subnet /// /// It creates an instance of a MySqlLeaseStatsQuery6 for a single subnet @@ -733,9 +759,11 @@ public: ALL_LEASE4_STATS, // Fetches IPv4 lease statistics SUBNET_LEASE4_STATS, // Fetched IPv4 lease stats for a single subnet. SUBNET_RANGE_LEASE4_STATS, // Fetched IPv4 lease stats for a subnet range. + ALL_POOL_LEASE4_STATS, // Fetches IPv4 lease pool statistics ALL_LEASE6_STATS, // Fetches IPv6 lease statistics SUBNET_LEASE6_STATS, // Fetched IPv6 lease stats for a single subnet. SUBNET_RANGE_LEASE6_STATS, // Fetched IPv6 lease stats for a subnet range. + ALL_POOL_LEASE6_STATS, // Fetches IPv6 lease pool statistics CHECK_LEASE4_LIMITS, // Check if allocated IPv4 leases are inside the set limits. CHECK_LEASE6_LIMITS, // Check if allocated IPv6 leases are inside the set limits. IS_JSON_SUPPORTED, // Checks if JSON support is enabled in the database. diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 4646ecf629..9cd4b35acb 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -44,24 +44,24 @@ PgSqlTaggedStatement tagged_statements[] = { // DELETE_LEASE4 { 2, { OID_INT8, OID_TIMESTAMP }, "delete_lease4", - "DELETE FROM lease4 WHERE address = $1 AND expire = $2"}, + "DELETE FROM lease4 WHERE address = $1 AND expire = $2" }, // DELETE_LEASE4_STATE_EXPIRED { 2, { OID_INT8, OID_TIMESTAMP }, "delete_lease4_state_expired", "DELETE FROM lease4 " - "WHERE state = $1 AND expire < $2"}, + "WHERE state = $1 AND expire < $2" }, // DELETE_LEASE6 { 2, { OID_VARCHAR, OID_TIMESTAMP }, "delete_lease6", - "DELETE FROM lease6 WHERE address = $1 AND expire = $2"}, + "DELETE FROM lease6 WHERE address = $1 AND expire = $2" }, // DELETE_LEASE6_STATE_EXPIRED { 2, { OID_INT8, OID_TIMESTAMP }, "delete_lease6_state_expired", "DELETE FROM lease6 " - "WHERE state = $1 AND expire < $2"}, + "WHERE state = $1 AND expire < $2" }, // GET_LEASE4 { 0, { OID_NONE }, @@ -70,7 +70,7 @@ PgSqlTaggedStatement tagged_statements[] = { "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " - "FROM lease4"}, + "FROM lease4" }, // GET_LEASE4_ADDR { 1, { OID_INT8 }, @@ -80,7 +80,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE address = $1"}, + "WHERE address = $1" }, // GET_LEASE4_CLIENTID { 1, { OID_BYTEA }, @@ -90,7 +90,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE client_id = $1"}, + "WHERE client_id = $1" }, // GET_LEASE4_CLIENTID_SUBID { 2, { OID_BYTEA, OID_INT8 }, @@ -100,7 +100,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE client_id = $1 AND subnet_id = $2"}, + "WHERE client_id = $1 AND subnet_id = $2" }, // GET_LEASE4_HWADDR { 1, { OID_BYTEA }, @@ -110,7 +110,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE hwaddr = $1"}, + "WHERE hwaddr = $1" }, // GET_LEASE4_HWADDR_SUBID { 2, { OID_BYTEA, OID_INT8 }, @@ -120,7 +120,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE hwaddr = $1 AND subnet_id = $2"}, + "WHERE hwaddr = $1 AND subnet_id = $2" }, // GET_LEASE4_PAGE { 2, { OID_INT8, OID_INT8 }, @@ -132,7 +132,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease4 " "WHERE address > $1 " "ORDER BY address " - "LIMIT $2"}, + "LIMIT $2" }, // GET_LEASE4_UCTX_PAGE { 2, { OID_INT8, OID_INT8 }, @@ -140,7 +140,7 @@ PgSqlTaggedStatement tagged_statements[] = { "SELECT address, hwaddr, client_id, " "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, " "fqdn_fwd, fqdn_rev, hostname, " - "state, user_context, relay_id, remote_id " + "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " "WHERE address > $1 AND user_context IS NOT NULL " "ORDER BY address " @@ -154,7 +154,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE subnet_id = $1"}, + "WHERE subnet_id = $1" }, // GET_LEASE4_HOSTNAME { 1, { OID_VARCHAR }, @@ -164,7 +164,7 @@ PgSqlTaggedStatement tagged_statements[] = { "fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id " "FROM lease4 " - "WHERE lower(hostname) = $1"}, + "WHERE lower(hostname) = $1" }, // GET_LEASE4_EXPIRE { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, @@ -176,7 +176,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease4 " "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 " "ORDER BY expire " - "LIMIT $3"}, + "LIMIT $3" }, // GET_LEASE4_RELAYID { 3, { OID_BYTEA, OID_INT8, OID_INT8 }, @@ -188,7 +188,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease4 " "WHERE relay_id = $1 and address > $2 " "ORDER BY address " - "LIMIT $3"}, + "LIMIT $3" }, // GET_LEASE4_RELAYID_QST { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 }, @@ -202,7 +202,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) >= $3 " "ORDER BY address " - "LIMIT $4"}, + "LIMIT $4" }, // GET_LEASE4_RELAYID_QSET { 5, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8, OID_INT8 }, @@ -218,7 +218,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) <= $4 " "ORDER BY address " - "LIMIT $5"}, + "LIMIT $5" }, // GET_LEASE4_RELAYID_QET { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 }, @@ -232,7 +232,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) <= $3 " "ORDER BY address " - "LIMIT $4"}, + "LIMIT $4" }, // GET_LEASE4_REMOTEID { 3, { OID_BYTEA, OID_INT8, OID_INT8 }, @@ -244,7 +244,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease4 " "WHERE remote_id = $1 and address > $2 " "ORDER BY address " - "LIMIT $3"}, + "LIMIT $3" }, // GET_LEASE4_REMOTEID_QST { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 }, @@ -258,7 +258,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) >= $3 " "ORDER BY address " - "LIMIT $4"}, + "LIMIT $4" }, // GET_LEASE4_REMOTEID_QSET { 5, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8, OID_INT8 }, @@ -274,7 +274,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) <= $4 " "ORDER BY address " - "LIMIT $5"}, + "LIMIT $5" }, // GET_LEASE4_REMOTEID_QET { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 }, @@ -288,7 +288,7 @@ PgSqlTaggedStatement tagged_statements[] = { "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 " "THEN 0 ELSE valid_lifetime END) <= $3 " "ORDER BY address " - "LIMIT $4"}, + "LIMIT $4" }, // GET_LEASE6 { 0, { OID_NONE }, @@ -298,7 +298,7 @@ PgSqlTaggedStatement tagged_statements[] = { "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " - "FROM lease6"}, + "FROM lease6" }, // GET_LEASE6_ADDR { 2, { OID_VARCHAR, OID_INT2 }, @@ -309,7 +309,7 @@ PgSqlTaggedStatement tagged_statements[] = { "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " "FROM lease6 " - "WHERE address = $1 AND lease_type = $2"}, + "WHERE address = $1 AND lease_type = $2" }, // GET_LEASE6_DUID_IAID { 3, { OID_BYTEA, OID_INT8, OID_INT2 }, @@ -320,7 +320,7 @@ PgSqlTaggedStatement tagged_statements[] = { "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " "FROM lease6 " - "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"}, + "WHERE duid = $1 AND iaid = $2 AND lease_type = $3" }, // GET_LEASE6_DUID_IAID_SUBID { 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 }, @@ -332,7 +332,7 @@ PgSqlTaggedStatement tagged_statements[] = { "state, user_context, pool_id " "FROM lease6 " "WHERE lease_type = $1 " - "AND duid = $2 AND iaid = $3 AND subnet_id = $4"}, + "AND duid = $2 AND iaid = $3 AND subnet_id = $4" }, // GET_LEASE6_PAGE { 2, { OID_VARCHAR, OID_INT8 }, @@ -345,7 +345,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease6 " "WHERE address > $1 " "ORDER BY address " - "LIMIT $2"}, + "LIMIT $2" }, // GET_LEASE6_UCTX_PAGE { 2, { OID_VARCHAR, OID_INT8 }, @@ -354,7 +354,7 @@ PgSqlTaggedStatement tagged_statements[] = { "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " "hwaddr, hwtype, hwaddr_source, " - "state, user_context " + "state, user_context, pool_id " "FROM lease6 " "WHERE address > $1 AND user_context IS NOT NULL " "ORDER BY address " @@ -382,7 +382,7 @@ PgSqlTaggedStatement tagged_statements[] = { "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " "FROM lease6 " - "WHERE subnet_id = $1"}, + "WHERE subnet_id = $1" }, // GET_LEASE6_DUID { 1, { OID_BYTEA }, @@ -393,7 +393,7 @@ PgSqlTaggedStatement tagged_statements[] = { "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " "FROM lease6 " - "WHERE duid = $1"}, + "WHERE duid = $1" }, // GET_LEASE6_HOSTNAME { 1, { OID_VARCHAR }, @@ -404,7 +404,7 @@ PgSqlTaggedStatement tagged_statements[] = { "hwaddr, hwtype, hwaddr_source, " "state, user_context, pool_id " "FROM lease6 " - "WHERE lower(hostname) = $1"}, + "WHERE lower(hostname) = $1" }, // GET_LEASE6_EXPIRE { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 }, @@ -418,7 +418,7 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease6 " "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 " "ORDER BY expire " - "LIMIT $3"}, + "LIMIT $3" }, // GET_LEASE6_LINK { 3, { OID_BYTEA, OID_BYTEA, OID_INT8 }, @@ -442,7 +442,7 @@ PgSqlTaggedStatement tagged_statements[] = { "INSERT INTO lease4(address, hwaddr, client_id, " "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, " "state, user_context, relay_id, remote_id, pool_id) " - "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)"}, + "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)" }, // INSERT_LEASE6 { 19, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, @@ -455,7 +455,7 @@ PgSqlTaggedStatement tagged_statements[] = { "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " "hwaddr, hwtype, hwaddr_source, " "state, user_context, binaddr, pool_id) " - "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)"}, + "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)" }, // UPDATE_LEASE4 { 16, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, @@ -466,7 +466,7 @@ PgSqlTaggedStatement tagged_statements[] = { "client_id = $3, valid_lifetime = $4, expire = $5, " "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, " "state = $10, user_context = $11, relay_id = $12, remote_id = $13, pool_id = $14 " - "WHERE address = $15 AND expire = $16"}, + "WHERE address = $15 AND expire = $16" }, // UPDATE_LEASE6 { 21, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8, @@ -480,13 +480,13 @@ 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, binaddr = $18, pool_id = $19 " - "WHERE address = $20 AND expire = $21"}, + "WHERE address = $20 AND expire = $21" }, // ALL_LEASE4_STATS { 0, { OID_NONE }, "all_lease4_stats", "SELECT subnet_id, state, leases as state_count" - " FROM lease4_stat ORDER BY subnet_id, state"}, + " FROM lease4_stat ORDER BY subnet_id, state" }, // SUBNET_LEASE4_STATS { 1, { OID_INT8 }, @@ -494,7 +494,7 @@ PgSqlTaggedStatement tagged_statements[] = { "SELECT subnet_id, state, leases as state_count" " FROM lease4_stat " " WHERE subnet_id = $1 " - " ORDER BY state"}, + " ORDER BY state" }, // SUBNET_RANGE_LEASE4_STATS { 2, { OID_INT8, OID_INT8 }, @@ -502,13 +502,19 @@ PgSqlTaggedStatement tagged_statements[] = { "SELECT subnet_id, state, leases as state_count" " FROM lease4_stat " " WHERE subnet_id >= $1 and subnet_id <= $2 " - " ORDER BY subnet_id, state"}, + " ORDER BY subnet_id, state" }, + + // ALL_POOL_LEASE4_STATS + { 0, { OID_NONE }, + "all_pool_lease4_stats", + "SELECT subnet_id, pool_id, state, leases as state_count" + " FROM lease4_pool_stat ORDER BY subnet_id, pool_id, state" }, // ALL_LEASE6_STATS, { 0, { OID_NONE }, - "all_lease6_stats", - "SELECT subnet_id, lease_type, state, leases as state_count" - " FROM lease6_stat ORDER BY subnet_id, lease_type, state" }, + "all_lease6_stats", + "SELECT subnet_id, lease_type, state, leases as state_count" + " FROM lease6_stat ORDER BY subnet_id, lease_type, state" }, // SUBNET_LEASE6_STATS { 1, { OID_INT8 }, @@ -526,6 +532,12 @@ PgSqlTaggedStatement tagged_statements[] = { " WHERE subnet_id >= $1 and subnet_id <= $2 " " ORDER BY subnet_id, lease_type, state" }, + // ALL_POOL_LEASE6_STATS, + { 0, { OID_NONE }, + "all_pool_lease6_stats", + "SELECT subnet_id, pool_id, lease_type, state, leases as state_count" + " FROM lease6_pool_stat ORDER BY subnet_id, pool_id, lease_type, state" }, + // CHECK_LEASE4_LIMITS { 1, { OID_TEXT }, "check_lease4_limits", @@ -546,14 +558,14 @@ PgSqlTaggedStatement tagged_statements[] = { "get_lease4_count_by_class", "SELECT leases " "FROM lease4_stat_by_client_class " - "WHERE client_class = $1"}, + "WHERE client_class = $1" }, // GET_LEASE6_COUNT_BY_CLASS { 2, { OID_VARCHAR, OID_INT2 }, "get_lease6_count_by_class", "SELECT leases " "FROM lease6_stat_by_client_class " - "WHERE client_class = $1 AND lease_type = $2"}, + "WHERE client_class = $1 AND lease_type = $2" }, // End of list sentinel { 0, { 0 }, NULL, NULL} @@ -1274,10 +1286,11 @@ public: /// @param statement The lease data SQL prepared statement to execute /// @param fetch_type Indicates whether or not lease_type should be /// fetched from the result set + /// @param fetch_pool Indicates if query requires pool data PgSqlLeaseStatsQuery(PgSqlConnection& conn, PgSqlTaggedStatement& statement, - const bool fetch_type) + const bool fetch_type, const bool fetch_pool = false) : conn_(conn), statement_(statement), result_set_(), next_row_(0), - fetch_type_(fetch_type) { + fetch_type_(fetch_type), fetch_pool_(fetch_pool) { } /// @brief Constructor to query for a single subnet's stats @@ -1291,7 +1304,7 @@ public: PgSqlLeaseStatsQuery(PgSqlConnection& conn, PgSqlTaggedStatement& statement, const bool fetch_type, const SubnetID& subnet_id) : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(), - next_row_(0), fetch_type_(fetch_type) { + next_row_(0), fetch_type_(fetch_type), fetch_pool_(false) { } /// @brief Constructor to query for the stats for a range of subnets @@ -1308,7 +1321,7 @@ public: const bool fetch_type, const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement), - result_set_(), next_row_(0), fetch_type_(fetch_type) { + result_set_(), next_row_(0), fetch_type_(fetch_type), fetch_pool_(false) { } /// @brief Destructor @@ -1325,7 +1338,7 @@ public: /// a first and last subnet id for a subnet range. void start() { - if (getSelectMode() == ALL_SUBNETS) { + if (getSelectMode() == ALL_SUBNETS || getSelectMode() == ALL_SUBNET_POOLS) { // Run the query with no where clause parameters. result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name, 0, 0, 0, 0, 0))); @@ -1378,6 +1391,13 @@ public: row.subnet_id_ = static_cast(subnet_id); ++col; + // Fetch the pool id if we were told to do so. + if (fetch_pool_) { + PgSqlExchange::getColumnValue(*result_set_, next_row_ , col, + row.pool_id_); + ++col; + } + // Fetch the lease type if we were told to do so. if (fetch_type_) { uint32_t lease_type; @@ -1429,6 +1449,9 @@ protected: /// @brief Indicates if query supplies lease type bool fetch_type_; + /// @brief Indicates if query requires pool data + bool fetch_pool_; + /// @brief Received negative state count showing a problem static bool negative_count_; }; @@ -2751,6 +2774,19 @@ PgSqlLeaseMgr::startLeaseStatsQuery4() { return(query); } +LeaseStatsQueryPtr +PgSqlLeaseMgr::startPoolLeaseStatsQuery4() { + // Get a context + PgSqlLeaseContextAlloc get_context(*this); + PgSqlLeaseContextPtr ctx = get_context.ctx_; + + LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_, + tagged_statements[ALL_POOL_LEASE4_STATS], + false, true)); + query->start(); + return(query); +} + LeaseStatsQueryPtr PgSqlLeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) { // Get a context @@ -2794,6 +2830,19 @@ PgSqlLeaseMgr::startLeaseStatsQuery6() { return(query); } +LeaseStatsQueryPtr +PgSqlLeaseMgr::startPoolLeaseStatsQuery6() { + // Get a context + PgSqlLeaseContextAlloc get_context(*this); + PgSqlLeaseContextPtr ctx = get_context.ctx_; + + LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_, + tagged_statements[ALL_POOL_LEASE6_STATS], + true, true)); + query->start(); + return(query); +} + LeaseStatsQueryPtr PgSqlLeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) { // Get a context diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index 95fda12d2c..12435dd0a7 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -538,6 +538,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv4 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4() override; + /// @brief Creates and runs the IPv4 lease stats query for a single subnet /// /// It creates an instance of a PgSqlLeaseStatsQuery4 for a single subnet @@ -570,6 +583,19 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for all subnets and + /// pools + /// + /// LeaseMgr derivations implement this method such that it creates and + /// returns an instance of an LeaseStatsQuery whose result set has been + /// populated with up to date IPv6 lease statistical data for all subnets + /// and pools. + /// Each row of the result set is an LeaseStatRow which ordered ascending + /// by subnet ID and pool ID. + /// + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6() override; + /// @brief Creates and runs the IPv6 lease stats query for a single subnet /// /// It creates an instance of a PgSqlLeaseStatsQuery6 for a single subnet @@ -709,9 +735,11 @@ public: ALL_LEASE4_STATS, // Fetches IPv4 lease statistics SUBNET_LEASE4_STATS, // Fetched IPv4 lease stats for a single subnet. SUBNET_RANGE_LEASE4_STATS, // Fetched IPv4 lease stats for a subnet range. + ALL_POOL_LEASE4_STATS, // Fetches IPv4 lease pool statistics ALL_LEASE6_STATS, // Fetches IPv6 lease statistics SUBNET_LEASE6_STATS, // Fetched IPv6 lease stats for a single subnet. SUBNET_RANGE_LEASE6_STATS, // Fetched IPv6 lease stats for a subnet range. + ALL_POOL_LEASE6_STATS, // Fetches IPv6 lease pool statistics CHECK_LEASE4_LIMITS, // Check if allocated IPv4 leases are inside the set limits. CHECK_LEASE6_LIMITS, // Check if allocated IPv6 leases are inside the set limits. IS_JSON_SUPPORTED, // Checks if JSON support is enabled in the database. diff --git a/src/lib/dhcpsrv/tests/lease_unittest.cc b/src/lib/dhcpsrv/tests/lease_unittest.cc index 35cdb52394..b63131b888 100644 --- a/src/lib/dhcpsrv/tests/lease_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_unittest.cc @@ -142,118 +142,6 @@ TEST_F(Lease4Test, constructor) { } } -// This test verifies that copy constructor copies Lease4 fields correctly. -TEST_F(Lease4Test, copyConstructor) { - - // Get current time for the use in Lease4. - const time_t current_time = time(0); - - // Create the lease - Lease4 lease(0xffffffff, hwaddr_, clientid_, VALID_LIFETIME, current_time, - SUBNET_ID); - - // Declined is a non-default state. We'll see if the state will be copied - // or the default state will be set for the copied lease. - lease.state_ = Lease::STATE_DECLINED; - - // Set an user context. - lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }")); - - // Set relay and remote id. - const std::vector relay_id = { 0xaa, 0xbb, 0xcc }; - lease.relay_id_ = relay_id; - const std::vector remote_id = { 1, 2, 3 }; - lease.remote_id_ = remote_id; - - // Use copy constructor to copy the lease. - Lease4 copied_lease(lease); - - // Both leases should be now equal. When doing this check we assume that - // the equality operator works correctly. - EXPECT_TRUE(lease == copied_lease); - // Client IDs are equal, but they should be in two distinct pointers. - EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_); - - // User context are equal and point to the same object. - ASSERT_TRUE(copied_lease.getContext()); - EXPECT_TRUE(lease.getContext() == copied_lease.getContext()); - EXPECT_TRUE(*lease.getContext() == *copied_lease.getContext()); - - // Relay and remote ids are equal. - EXPECT_TRUE(lease.relay_id_ == copied_lease.relay_id_); - EXPECT_TRUE(lease.remote_id_ == copied_lease.remote_id_); - - // Hardware addresses are equal, but they should point to two objects, - // each holding the same data. The content should be equal... - EXPECT_TRUE(*lease.hwaddr_ == *copied_lease.hwaddr_); - - // ... but it should point to different objects. - EXPECT_FALSE(lease.hwaddr_ == copied_lease.hwaddr_); - - // Now let's check that the hwaddr pointer is copied even if it's null: - lease.hwaddr_.reset(); - Lease4 copied_lease2(lease); - EXPECT_TRUE(lease == copied_lease2); -} - -// This test verifies that the assignment operator copies all Lease4 fields -// correctly. -TEST_F(Lease4Test, operatorAssign) { - - // Get the current time for the use in Lease4. - const time_t current_time = time(0); - - // Create the lease - Lease4 lease(0xffffffff, hwaddr_, clientid_, VALID_LIFETIME, current_time, - SUBNET_ID); - - // Declined is a non-default state. We'll see if the state will be copied - // or the default state will be set for the copied lease. - lease.state_ = Lease::STATE_DECLINED; - - // Set an user context. - lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }")); - - // Set relay and remote id. - const std::vector relay_id = { 0xaa, 0xbb, 0xcc }; - lease.relay_id_ = relay_id; - const std::vector remote_id = { 1, 2, 3 }; - lease.remote_id_ = remote_id; - - // Create a default lease. - Lease4 assigned_lease; - // Use assignment operator to assign new lease. - assigned_lease = lease; - - // Both leases should be now equal. When doing this check we assume that - // the equality operator works correctly. - EXPECT_TRUE(lease == assigned_lease); - // Client IDs are equal, but they should be in two distinct pointers. - EXPECT_FALSE(lease.client_id_ == assigned_lease.client_id_); - - // User context are equal and point to the same object. - ASSERT_TRUE(assigned_lease.getContext()); - EXPECT_TRUE(lease.getContext() == assigned_lease.getContext()); - EXPECT_TRUE(*lease.getContext() == *assigned_lease.getContext()); - - // User context are equal and point to the same object. - ASSERT_TRUE(assigned_lease.getContext()); - EXPECT_TRUE(lease.getContext() == assigned_lease.getContext()); - EXPECT_TRUE(*lease.getContext() == *assigned_lease.getContext()); - - // Hardware addresses are equal, but they should point to two objects, - // each holding the same data. The content should be equal... - EXPECT_TRUE(*lease.hwaddr_ == *assigned_lease.hwaddr_); - - // ... but it should point to different objects. - EXPECT_FALSE(lease.hwaddr_ == assigned_lease.hwaddr_); - - // Now let's check that the hwaddr pointer is copied even if it's null: - lease.hwaddr_.reset(); - assigned_lease = lease; - EXPECT_TRUE(lease == assigned_lease); -} - // This test verifies that it is correctly determined when the lease // belongs to the particular client identified by the client identifier // and hw address. diff --git a/src/lib/dhcpsrv/tracking_lease_mgr.cc b/src/lib/dhcpsrv/tracking_lease_mgr.cc index a245c138f3..d9301246ef 100644 --- a/src/lib/dhcpsrv/tracking_lease_mgr.cc +++ b/src/lib/dhcpsrv/tracking_lease_mgr.cc @@ -158,6 +158,5 @@ TrackingLeaseMgr::runCallbacksForSubnetID(CallbackType type, SubnetID subnet_id, } } - } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/lib/dhcpsrv/tracking_lease_mgr.h b/src/lib/dhcpsrv/tracking_lease_mgr.h index 31e91c6de8..62928c5ac3 100644 --- a/src/lib/dhcpsrv/tracking_lease_mgr.h +++ b/src/lib/dhcpsrv/tracking_lease_mgr.h @@ -312,5 +312,4 @@ protected: } // end of namespace isc::dhcp } // end of namespace isc - #endif // TRACKING_LEASE_MGR_H -- 2.47.2