Browse Source

[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
Thomas Markwalder 8 years ago
parent
commit
4a94a1f7b9

+ 2 - 2
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

+ 169 - 0
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<AddressStatsRow6> rows_;
+
+    /// @brief An iterator for accessing the next row within the result set
+    std::vector<AddressStatsRow6>::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<SubnetIdIndexTag>();
+
+    // 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

+ 9 - 0
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.

+ 13 - 0
src/lib/dhcpsrv/memfile_lease_storage.h

@@ -106,7 +106,17 @@ typedef boost::multi_index_container<
                 boost::multi_index::const_mem_fun<Lease, int64_t,
                                                   &Lease::getExpirationTime>
             >
+        >,
+
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<SubnetIdIndexTag>,
+            // 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<Lease, SubnetID, &Lease::subnet_id_>
         >
+
      >
 > Lease6Storage; // Specify the type name of this container.
 
@@ -241,6 +251,9 @@ typedef Lease6Storage::index<DuidIaidTypeIndexTag>::type Lease6StorageDuidIaidTy
 /// @brief DHCPv6 lease storage index by expiration time.
 typedef Lease6Storage::index<ExpirationIndexTag>::type Lease6StorageExpirationIndex;
 
+/// @brief DHCPv6 lease storage index by subnet id.
+typedef Lease6Storage::index<SubnetIdIndexTag>::type Lease6StorageSubnetIdIndex;
+
 /// @brief DHCPv4 lease storage index by address.
 typedef Lease4Storage::index<AddressIndexTag>::type Lease4StorageAddressIndex;
 

+ 6 - 0
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