From: Thomas Markwalder Date: Tue, 16 Aug 2016 18:15:25 +0000 (-0400) Subject: [4294] Memfile now supports IPv6 lease stats recounting X-Git-Tag: trac4631_base~6^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a94a1f7b9b46dcecbf1c0fd2ceb4532cbd80be7;p=thirdparty%2Fkea.git [4294] Memfile now supports IPv6 lease stats recounting src/lib/dhcpsrv/memfile_lease_mgr.h src/lib/dhcpsrv/memfile_lease_mgr.cc - MemfileAddressStatsQuery6 - new class, Memfile derivation of the IPv6 statistical lease data query - Memfile_LeaseMgr::startAddressStatsQuery6() - new virtual method that creates and runs the IPv6 lease stats query src/lib/dhcpsrv/memfile_lease_storage.h - Added non-unique index on subnet ID to Lease6Storage src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc TEST_F(MemfileLeaseMgrTest, recountAddressStats6) - new test --- diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 140a7d1c72..f0a58f7aef 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -229,8 +229,8 @@ struct AddressStatsRow6 { AddressStatsRow6(const SubnetID& subnet_id, const Lease::Type& lease_type, const Lease::LeaseState& lease_state, const int64_t state_count) - : subnet_id_(subnet_id), lease_state_(lease_state), - state_count_(state_count) { + : subnet_id_(subnet_id), lease_type_(lease_type), + lease_state_(lease_state), state_count_(state_count) { } /// @brief The subnet ID to which this data applies diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 1ad41cd1c2..ceed6f473d 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -393,6 +393,168 @@ MemfileAddressStatsQuery4::getRowCount() { return (rows_.size()); } +/// @brief Memfile derivation of the IPv6 statistical lease data query +/// +/// This class is used to recalculate IPv6 lease statistics for Memfile +/// lease storage. It does so by iterating over the given storage, +/// accumulating counts of leases in each of the monitored lease states +/// for each subnet and storing these counts in an internal collection. +/// The populated result set will contain one entry per monitored state +/// per subnet. +/// +class MemfileAddressStatsQuery6 : public AddressStatsQuery6 { +public: + /// @brief Constructor + /// + /// @param storage6 A pointer to the v6 lease storage to be counted + MemfileAddressStatsQuery6(Lease6Storage& storage6); + + /// @brief Destructor + virtual ~MemfileAddressStatsQuery6() {}; + + /// @brief Creates the IPv6 lease statistical data result set + /// + /// The result is populated by iterating over the IPv6 leases in storage, + /// in ascending order by subnet ID, accumulating the lease state counts + /// per lease type. At the completion of all entries for a given subnet, + /// the counts are used to create AddressStatsRow5 instances which are + /// appended to an internal vector. The process results in a vector + /// containing one entry per state per lease type per subnet. + /// + /// Currently the states counted are: + /// + /// - Lease::STATE_DEFAULT (i.e. assigned) + /// - Lease::STATE_DECLINED + virtual void start(); + + /// @brief Fetches the next row in the result set + /// + /// Once the internal result set has been populated by invoking the + /// the start() method, this method is used to iterate over the + /// result set rows. Once the last row has been fetched, subsequent + /// calls will return false. + /// @param row Storage for the fetched row + /// + /// @return True if the fetch succeeded, false if there are no more + /// rows to fetch. + virtual bool getNextRow(AddressStatsRow6& row); + + /// @brief Returns the number of rows in the result set + /// @todo, should this be a virtual member of the base class? + int getRowCount(); + +private: + /// @brief The Memfile storage containing the IPv6 leases to analyze + Lease6Storage& storage6_; + + /// @brief A vector containing the "result set" + std::vector rows_; + + /// @brief An iterator for accessing the next row within the result set + std::vector::iterator next_pos_; +}; + +MemfileAddressStatsQuery6::MemfileAddressStatsQuery6(Lease6Storage& storage6) + : storage6_(storage6), rows_(0), next_pos_(rows_.end()) {}; + +void +MemfileAddressStatsQuery6::start() { + // Get the subnet_id index + const Lease6StorageSubnetIdIndex& idx = storage6_.get(); + + // 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; + int64_t assigned = 0; + int64_t declined = 0; + int64_t assigned_pds = 0; + + for(Lease6StorageSubnetIdIndex::const_iterator lease = idx.begin(); + lease != idx.end(); ++lease) { + + // 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) { + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_NA, + Lease::STATE_DEFAULT, + assigned)); + assigned = 0; + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_NA, + Lease::STATE_DECLINED, + declined)); + declined = 0; + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_PD, + Lease::STATE_DEFAULT, + assigned_pds)); + assigned_pds = 0; + } + + // Update current subnet id + cur_id = (*lease)->subnet_id_; + } + + // Bump the appropriate accumulator + switch ((*lease)->state_) { + case Lease::STATE_DEFAULT: + switch((*lease)->type_) { + case Lease::TYPE_NA: + ++assigned; + break; + case Lease::TYPE_PD: + ++assigned_pds; + break; + default: + break; + } + break; + case Lease::STATE_DECLINED: + // In theory only NAs can be declined + if (((*lease)->type_) == Lease::TYPE_NA) { + ++declined; + } + break; + default: + // Not one we're tracking. + break; + } + } + + // Make the rows for last subnet, unless there were no rows + if (idx.begin() != idx.end()) { + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_NA, + Lease::STATE_DEFAULT, + assigned)); + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_NA, + Lease::STATE_DECLINED, + declined)); + rows_.push_back(AddressStatsRow6(cur_id, Lease::TYPE_PD, + Lease::STATE_DEFAULT, + assigned_pds)); + } + + // Set the next row position to the beginning of the rows. + next_pos_ = rows_.begin(); +} + +bool +MemfileAddressStatsQuery6::getNextRow(AddressStatsRow6& row) { + if (next_pos_ == rows_.end()) { + return (false); + } + + row = *next_pos_; + ++next_pos_; + return (true); +} + +int +MemfileAddressStatsQuery6::getRowCount() { + return (rows_.size()); +} + + // Explicit definition of class static constants. Values are given in the // declaration so they're not needed here. const int Memfile_LeaseMgr::MAJOR_VERSION; @@ -1193,5 +1355,12 @@ Memfile_LeaseMgr::startAddressStatsQuery4() { return(query); } +AddressStatsQuery6Ptr +Memfile_LeaseMgr::startAddressStatsQuery6() { + AddressStatsQuery6Ptr query(new MemfileAddressStatsQuery6(storage6_)); + query->start(); + return(query); +} + } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index 8bc4c72b85..d4e7c1a94a 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -604,6 +604,15 @@ public: /// @return The populated query as a pointer to an AddressStatsQuery4 virtual AddressStatsQuery4Ptr startAddressStatsQuery4(); + /// @brief Creates and runs the IPv6 lease stats query + /// + /// It creates an instance of a MemfileAddressStatsQuery6 and then + /// invokes it's start method in which the query constructs its + /// statistical data result set. The query object is then returned. + /// + /// @return The populated query as a pointer to an AddressStatsQuery6 + virtual AddressStatsQuery6Ptr startAddressStatsQuery6(); + /// @name Protected methods used for %Lease File Cleanup. /// The following methods are protected so as they can be accessed and /// tested by unit tests. diff --git a/src/lib/dhcpsrv/memfile_lease_storage.h b/src/lib/dhcpsrv/memfile_lease_storage.h index fba499672f..5c09f35d56 100644 --- a/src/lib/dhcpsrv/memfile_lease_storage.h +++ b/src/lib/dhcpsrv/memfile_lease_storage.h @@ -106,7 +106,17 @@ typedef boost::multi_index_container< boost::multi_index::const_mem_fun > + >, + + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + // The subnet id is held in the subnet_id_ member of Lease6 + // class. Note that the subnet_id_ is defined in the base + // class (Lease) so we have to point to this class rather + // than derived class: Lease6. + boost::multi_index::member > + > > Lease6Storage; // Specify the type name of this container. @@ -241,6 +251,9 @@ typedef Lease6Storage::index::type Lease6StorageDuidIaidTy /// @brief DHCPv6 lease storage index by expiration time. typedef Lease6Storage::index::type Lease6StorageExpirationIndex; +/// @brief DHCPv6 lease storage index by subnet id. +typedef Lease6Storage::index::type Lease6StorageSubnetIdIndex; + /// @brief DHCPv4 lease storage index by address. typedef Lease4Storage::index::type Lease4StorageAddressIndex; diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index 3cf45d58d6..1379cf1c14 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -1889,4 +1889,10 @@ TEST_F(MemfileLeaseMgrTest, recountAddressStats4) { testRecountAddressStats4(); } +// Verifies that IPv6 lease statistics can be recalculated. +TEST_F(MemfileLeaseMgrTest, recountAddressStats6) { + startBackend(V6); + testRecountAddressStats6(); +} + }; // end of anonymous namespace