]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5651] Implemented fetching IPv6 leases with paging.
authorMarcin Siodelski <marcin@isc.org>
Tue, 26 Jun 2018 08:27:07 +0000 (10:27 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 26 Jun 2018 08:27:07 +0000 (10:27 +0200)
17 files changed:
src/lib/dhcpsrv/cql_lease_mgr.cc
src/lib/dhcpsrv/cql_lease_mgr.h
src/lib/dhcpsrv/dhcpsrv_messages.mes
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/mysql_lease_mgr.cc
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc

index 377efc3ddd8d4cc1a05bdb2598acc82a3d9ecb0b..a63e73a7b8a3d25e382d6bd34bf28bfaa0b808a7 100644 (file)
@@ -879,6 +879,9 @@ public:
     static constexpr StatementTag GET_LEASE6_ADDR = "GET_LEASE6_ADDR";
     static constexpr StatementTag GET_LEASE6_DUID_IAID = "GET_LEASE6_DUID_IAID";
     static constexpr StatementTag GET_LEASE6_DUID_IAID_SUBID = "GET_LEASE6_DUID_IAID_SUBID";
+    static constexpr StatementTag GET_LEASE6_LIMIT = "GET_LEASE6_LIMIT";
+    static constexpr StatementTag GET_LEASE6_PAGE = "GET_LEASE6_PAGE";
+    static constexpr StatementTag GET_LEASE6_RANGE = "GET_LEASE6_RANGE";
     // @}
 
 private:
@@ -917,6 +920,9 @@ constexpr StatementTag CqlLease6Exchange::GET_LEASE6_EXPIRE;
 constexpr StatementTag CqlLease6Exchange::GET_LEASE6_ADDR;
 constexpr StatementTag CqlLease6Exchange::GET_LEASE6_DUID_IAID;
 constexpr StatementTag CqlLease6Exchange::GET_LEASE6_DUID_IAID_SUBID;
+constexpr StatementTag CqlLease6Exchange::GET_LEASE6_LIMIT;
+constexpr StatementTag CqlLease6Exchange::GET_LEASE6_PAGE;
+constexpr StatementTag CqlLease6Exchange::GET_LEASE6_RANGE;
 
 StatementMap CqlLease6Exchange::tagged_statements_ = {
 
@@ -1011,6 +1017,40 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
       "AND subnet_id = ? "
       "ALLOW FILTERING "}},
 
+    // Get range of IPv6 leases from first lease with a limit (paging)
+    {GET_LEASE6_LIMIT,
+     {GET_LEASE6_LIMIT,
+      "SELECT "
+      "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
+      "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
+      "hwaddr_source, state "
+      "FROM lease6 "
+      "LIMIT ? "
+      "ALLOW FILTERING "}},
+
+    // Get range of IPv6 leases from address with a limit (paging)
+    {GET_LEASE6_PAGE,
+     {GET_LEASE6_PAGE,
+      "SELECT "
+      "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
+      "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
+      "hwaddr_source, state "
+      "FROM lease6 "
+      "WHERE TOKEN(address) > TOKEN(?) "
+      "LIMIT ? "
+      "ALLOW FILTERING "}},
+
+    // Get range of IPv6 leases between two addresses
+    {GET_LEASE6_RANGE,
+     {GET_LEASE6_RANGE,
+      "SELECT "
+      "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
+      "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
+      "hwaddr_source, state "
+      "FROM lease6 "
+      "WHERE address >= ? "
+      "AND address <= ? "
+      "ALLOW FILTERING "}},
 };
 
 CqlLease6Exchange::CqlLease6Exchange(const CqlConnection &connection)
@@ -1427,9 +1467,6 @@ CqlLease6Exchange::retrieve() {
 void
 CqlLease6Exchange::getLeaseCollection(StatementTag &statement_tag, AnyArray &data,
                                       Lease6Collection &result) {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_ADDR4)
-        .arg(statement_tag);
-
     AnyArray collection = executeSelect(connection_, data, statement_tag);
 
     // Transfer Lease6 objects to result.
@@ -2289,6 +2326,52 @@ CqlLeaseMgr::getLeases6() const {
     isc_throw(NotImplemented, "getLeases6() is not implemented");
 }
 
+Lease6Collection
+CqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
+                        const LeasePageSize& page_size) const {
+    if (page_size.page_size_ == 0) {
+        isc_throw(OutOfRange, "page size of retrieved leases must not be 0");
+    }
+
+    if (page_size.page_size_ > std::numeric_limits<uint32_t>::max()) {
+        isc_throw(OutOfRange, "page size of retrieved leases must not be greater than "
+                  << std::numeric_limits<uint32_t>::max());
+    }
+
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_PAGE6)
+        .arg(page_size.page_size_)
+        .arg(lower_bound_address.toText());
+
+    AnyArray data;
+
+    std::string lb_address_data;
+    if (!lower_bound_address.isV6Zero()) {
+        lb_address_data = lower_bound_address.toText();
+        if (lb_address_data.size() > ADDRESS6_TEXT_MAX_LEN) {
+            isc_throw(BadValue,
+                      "CqlLeaseMgr::getLeases6(lower_bound_address, page_size): "
+                      "address "
+                      << lb_address_data << " of length " << lb_address_data.size()
+                      << " exceeds maximum allowed length of "
+                      << ADDRESS6_TEXT_MAX_LEN);
+        }
+        data.add(&lb_address_data);
+    }
+
+    cass_int32_t page_size_data = static_cast<cass_int32_t>(page_size.page_size_);
+    data.add(&page_size_data);
+
+    // Get the leases.
+    Lease6Collection result;
+    std::unique_ptr<CqlLease6Exchange> exchange6(new CqlLease6Exchange(dbconn_));
+    exchange6->getLeaseCollection(lower_bound_address.isV6Zero() ?
+                                  CqlLease6Exchange::GET_LEASE6_LIMIT :
+                                  CqlLease6Exchange::GET_LEASE6_PAGE,
+                                  data, result);
+
+    return (result);
+}
+
 void
 CqlLeaseMgr::getExpiredLeases4(Lease4Collection &expired_leases,
                                const size_t max_leases) const {
index 6dc17f42655738e9bf7ec56d2020140be3f2f50d..ab4ffbaf24c8a1a488db709701b35b86a7cf5cc0 100644 (file)
@@ -333,6 +333,34 @@ public:
     /// this backend.
     virtual Lease6Collection getLeases6() const override;
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& lower_bound_address,
+               const LeasePageSize& page_size) const override;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 576be84cd15b05cd956cdd947dc1e6704d990427..9b26dd713518e5b60e178d291d47ee2d1e6b4986 100644 (file)
@@ -287,6 +287,10 @@ with addresses in the specified range.
 A debug message issued when the server is attempting to obtain a page
 of leases beginning with the specified address.
 
+% DHCPSRV_CQL_GET_PAGE6 obtaining at most %1 IPv6 leases starting from address %2
+A debug message issued when the server is attempting to obtain a page
+of leases beginning with the specified address.
+
 % DHCPSRV_CQL_GET_SUBID4 obtaining IPv4 leases for subnet ID %1
 A debug message issued when the server is attempting to obtain all IPv4
 leases for a given subnet identifier from the Cassandra database.
@@ -493,6 +497,10 @@ with addresses in the specified range.
 A debug message issued when the server is attempting to obtain a page
 of leases beginning with the specified address.
 
+% DHCPSRV_MEMFILE_GET_PAGE6 obtaining at most %1 IPv6 leases starting from address %2
+A debug message issued when the server is attempting to obtain a page
+of leases beginning with the specified address.
+
 % DHCPSRV_MEMFILE_GET6 obtaining all IPv6 leases
 A debug message issued when the server is attempting to obtain all IPv6
 leases from the memory file database.
@@ -753,6 +761,10 @@ with addresses in the specified range.
 A debug message issued when the server is attempting to obtain a page
 of leases beginning with the specified address.
 
+% DHCPSRV_MYSQL_GET_PAGE6 obtaining at most %1 IPv6 leases starting from address %2
+A debug message issued when the server is attempting to obtain a page
+of leases beginning with the specified address.
+
 % DHCPSRV_MYSQL_GET_ADDR6 obtaining IPv6 lease for address %1, lease type %2
 A debug message issued when the server is attempting to obtain an IPv6
 lease from the MySQL database for the specified address.
@@ -967,6 +979,10 @@ lease from the PostgreSQL database for a client with the specified IAID
 A debug message issued when the server is attempting to obtain a page
 of leases beginning with the specified address.
 
+% DHCPSRV_PGSQL_GET_PAGE6 obtaining at most %1 IPv6 leases starting from address %2
+A debug message issued when the server is attempting to obtain a page
+of leases beginning with the specified address.
+
 % DHCPSRV_PGSQL_GET_SUBID4 obtaining IPv4 leases for subnet ID %1
 A debug message issued when the server is attempting to obtain all IPv4
 leases for a given subnet identifier from the PostgreSQL database.
index 0e5ca9c256209979e20858fe6a7cd2fe08125795..2cb8ec9afc556a6995347d54f77afd768c344ff5 100644 (file)
@@ -488,6 +488,34 @@ public:
     /// @return Lease collection (may be empty if no IPv6 lease found).
     virtual Lease6Collection getLeases6() const = 0;
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& lower_bound_address,
+               const LeasePageSize& page_size) const = 0;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 5fb3c239a513b1324a6a2d611cf53cb02ba9532a..d0ada4d15830b40e40a17464a6879a4437aa6bfa 100644 (file)
@@ -1035,6 +1035,32 @@ Memfile_LeaseMgr::getLeases6() const {
    return (collection);
 }
 
+Lease6Collection
+Memfile_LeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
+                             const LeasePageSize& page_size) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE6)
+        .arg(page_size.page_size_)
+        .arg(lower_bound_address.toText());
+
+    Lease6Collection collection;
+    const Lease6StorageAddressIndex& idx = storage6_.get<AddressIndexTag>();
+    Lease6StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
+
+    // Exclude the lower bound address specified by the caller.
+    if ((lb != idx.end()) && ((*lb)->addr_ == lower_bound_address)) {
+        ++lb;
+    }
+
+    // Return all other leases being within the page size.
+    for (auto lease = lb;
+         (lease != idx.end()) && (std::distance(lb, lease) < page_size.page_size_);
+         ++lease) {
+        collection.push_back(Lease6Ptr(new Lease6(**lease)));
+    }
+
+    return (collection);
+}
+
 void
 Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                     const size_t max_leases) const {
index efb69175890b4492a5dd25913307b08f8c62c705..c80aa15b78187c2809ab58f61249375f9b5fdb8d 100644 (file)
@@ -327,6 +327,34 @@ public:
     /// @return Lease collection (may be empty if no IPv6 lease found).
     virtual Lease6Collection getLeases6() const;
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& lower_bound_address,
+               const LeasePageSize& page_size) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 76ae230aefabc5e87ee31b08cfe67a9bdb6d3b74..f0a4b5cb86d3af43266199e437bf3e39e6eeecb7 100644 (file)
@@ -206,6 +206,26 @@ tagged_statements = { {
                             "FROM lease6 "
                             "WHERE duid = ? AND iaid = ? AND subnet_id = ? "
                             "AND lease_type = ?"},
+    {MySqlLeaseMgr::GET_LEASE6_PAGE,
+                    "SELECT address, duid, valid_lifetime, "
+                        "expire, subnet_id, pref_lifetime, "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "hwaddr, hwtype, hwaddr_source, "
+                        "state "
+                            "FROM lease6 "
+                            "WHERE address > ? "
+                            "ORDER BY address "
+                            "LIMIT ?"},
+    {MySqlLeaseMgr::GET_LEASE6_RANGE,
+                    "SELECT address, duid, valid_lifetime, "
+                        "expire, subnet_id, pref_lifetime, "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "hwaddr, hwtype, hwaddr_source, "
+                        "state "
+                            "FROM lease6 "
+                            "WHERE address >= ? AND address <= ?"},
     {MySqlLeaseMgr::GET_LEASE6_SUBID,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
@@ -2140,6 +2160,45 @@ MySqlLeaseMgr::getLeases6() const {
     return (result);
 }
 
+Lease6Collection
+MySqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
+                          const LeasePageSize& page_size) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_PAGE6)
+        .arg(page_size.page_size_)
+        .arg(lower_bound_address.toText());
+
+    // Prepare WHERE clause
+    MYSQL_BIND inbind[2];
+    memset(inbind, 0, sizeof(inbind));
+
+    // In IPv6 we compare addresses represented as strings. The IPv6 zero address
+    // is ::, so it is greater than any other address. In this special case, we
+    // just use 0 for comparison which should be lower than any real IPv6 address.
+    std::string lb_address_data = "0";
+    if (!lower_bound_address.isV6Zero()) {
+        lb_address_data = lower_bound_address.toText();
+    }
+
+    // Bind lower bound address
+    unsigned long lb_address_data_size = lb_address_data.size();
+    inbind[0].buffer_type = MYSQL_TYPE_STRING;
+    inbind[0].buffer = const_cast<char*>(lb_address_data.c_str());
+    inbind[0].buffer_length = lb_address_data_size;
+    inbind[0].length = &lb_address_data_size;
+
+    // Bind page size value
+    size_t* ps = const_cast<size_t*>(&page_size.page_size_);
+    inbind[1].buffer_type = MYSQL_TYPE_LONG;
+    inbind[1].buffer = reinterpret_cast<char*>(ps);
+    inbind[1].is_unsigned = MLM_TRUE;
+
+    // Get the leases
+    Lease6Collection result;
+    getLeaseCollection(GET_LEASE6_PAGE, inbind, result);
+
+    return (result);
+}
+
 void
 MySqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                  const size_t max_leases) const {
index 5f320ad9228cad6a91b453af2091e76c02788432..24f70f76308a2917674e3d9192f7a6d04cfd2af7 100644 (file)
@@ -325,6 +325,34 @@ public:
     /// @return Lease collection (may be empty if no IPv6 lease found).
     virtual Lease6Collection getLeases6() const;
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& lower_bound_address,
+               const LeasePageSize& page_size) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
@@ -559,14 +587,16 @@ public:
         GET_LEASE4_CLIENTID_SUBID,   // Get lease4 by client ID & subnet ID
         GET_LEASE4_HWADDR,           // Get lease4 by HW address
         GET_LEASE4_HWADDR_SUBID,     // Get lease4 by HW address & subnet ID
-        GET_LEASE4_SUBID,            // Get IPv4 leases by subnet ID
         GET_LEASE4_PAGE,             // Get page of leases beginning with an address
         GET_LEASE4_RANGE,            // Get range of leases between addresses
+        GET_LEASE4_SUBID,            // Get IPv4 leases by subnet ID
         GET_LEASE4_EXPIRE,           // Get lease4 by expiration.
         GET_LEASE6,                  // Get all IPv6 leases
         GET_LEASE6_ADDR,             // Get lease6 by address
         GET_LEASE6_DUID_IAID,        // Get lease6 by DUID and IAID
         GET_LEASE6_DUID_IAID_SUBID,  // Get lease6 by DUID, IAID and subnet ID
+        GET_LEASE6_PAGE,             // Get page of leases beginning with an address
+        GET_LEASE6_RANGE,            // Get range of leases between addresses
         GET_LEASE6_SUBID,            // Get IPv6 leases by subnet ID
         GET_LEASE6_EXPIRE,           // Get lease6 by expiration.
         INSERT_LEASE4,               // Add entry to lease4 table
index 84030634c07ab1701301d796637243c829320edc..02dd997d4bf600cfaa193f9562124cad105f1f1c 100644 (file)
@@ -200,6 +200,30 @@ PgSqlTaggedStatement tagged_statements[] = {
       "WHERE lease_type = $1 "
         "AND duid = $2 AND iaid = $3 AND subnet_id = $4"},
 
+    // GET_LEASE6_PAGE
+    { 2, { OID_VARCHAR, OID_INT8 },
+      "get_lease6_page",
+      "SELECT address, duid, valid_lifetime, "
+        "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state "
+      "FROM lease6 "
+      "WHERE address > $1 "
+      "ORDER BY address "
+      "LIMIT $2"},
+
+    // GET_LEASE6_RANGE
+    { 2, { OID_VARCHAR, OID_VARCHAR },
+      "get_lease6_range",
+      "SELECT address, duid, valid_lifetime, "
+        "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state "
+      "FROM lease6 "
+      "WHERE address >= $1 AND address <= $2"},
+
     // GET_LEASE6_SUBID
     { 1, { OID_INT8 },
       "get_lease6_subid",
@@ -1491,6 +1515,38 @@ PgSqlLeaseMgr::getLeases6() const {
     return (result);
 }
 
+Lease6Collection
+PgSqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
+                             const LeasePageSize& page_size) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_PAGE6)
+        .arg(page_size.page_size_)
+        .arg(lower_bound_address.toText());
+
+    // Prepare WHERE clause
+    PsqlBindArray bind_array;
+
+    // In IPv6 we compare addresses represented as strings. The IPv6 zero address
+    // is ::, so it is greater than any other address. In this special case, we
+    // just use 0 for comparison which should be lower than any real IPv6 address.
+    std::string lb_address_data = "0";
+    if (!lower_bound_address.isV6Zero()) {
+        lb_address_data = lower_bound_address.toText();
+    }
+
+    // Bind lower bound address
+    bind_array.add(lb_address_data);
+
+    // Bind page size value
+    std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
+    bind_array.add(page_size_data);
+
+    // Get the leases
+    Lease6Collection result;
+    getLeaseCollection(GET_LEASE6_PAGE, bind_array, result);
+
+    return (result);
+}
+
 void
 PgSqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                  const size_t max_leases) const {
index 7ecf6fa8c1f2a866fbf42c90eb485ac6960ac8d0..e0287c9ac32f6e7e762cbb2f54dba73545c10d52 100644 (file)
@@ -297,6 +297,34 @@ public:
     /// @return Lease collection (may be empty if no IPv6 lease found).
     virtual Lease6Collection getLeases6() const;
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& lower_bound_address,
+               const LeasePageSize& page_size) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
@@ -535,6 +563,8 @@ public:
         GET_LEASE6_ADDR,            // Get lease6 by address
         GET_LEASE6_DUID_IAID,       // Get lease6 by DUID and IAID
         GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID
+        GET_LEASE6_PAGE,            // Get page of IPv6 leases beginning with an address
+        GET_LEASE6_RANGE,           // Get range of IPv6 leases between addresses
         GET_LEASE6_SUBID,           // Get IPv6 leases by subnet ID
         GET_LEASE6_EXPIRE,          // Get expired lease6
         INSERT_LEASE4,              // Add entry to lease4 table
index 5fa8b47757b27e6d6d9cee19629ceafae5762973..ba95b0b7c2dce0c181864d03f7c894a93c7d44cd 100644 (file)
@@ -697,6 +697,11 @@ TEST_F(CqlLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
     testGetLease6DuidIaidSubnetIdSize();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(CqlLeaseMgrTest, getLeases6Paged) {
+    testGetLeases6Paged();
+}
+
 /// @brief Lease6 update tests
 ///
 /// Checks that we are able to update a lease in the database.
index 601938205b79b4a3be83314d47a282119e0fabce..8f663516ad9df1d20f93d90800de6e9c8c04eb7d 100644 (file)
@@ -1259,7 +1259,7 @@ GenericLeaseMgrTest::testGetLeases4Paged() {
     Lease4Collection all_leases;
 
     IOAddress last_address = IOAddress("0.0.0.0");
-    for (auto i = 0; i < 1000; ++i) {
+    for (auto i = 0; i < 4; ++i) {
         Lease4Collection page = lmptr_->getLeases4(last_address, LeasePageSize(3));
 
         // Collect leases in a common structure. They may be out of order.
@@ -1371,6 +1371,55 @@ GenericLeaseMgrTest::testGetLeases6() {
     ASSERT_EQ(leases.size(), returned.size());
 }
 
+void
+GenericLeaseMgrTest::testGetLeases6Paged() {
+    // Get the leases to be used for the test and add to the database.
+    vector<Lease6Ptr> leases = createLeases6();
+    for (size_t i = 0; i < leases.size(); ++i) {
+        EXPECT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    Lease6Collection all_leases;
+
+    IOAddress last_address = IOAddress::IPV6_ZERO_ADDRESS();
+    for (auto i = 0; i < 4; ++i) {
+        Lease6Collection page = lmptr_->getLeases6(last_address, LeasePageSize(3));
+
+        // Collect leases in a common structure. They may be out of order.
+        for (Lease6Ptr lease : page) {
+            all_leases.push_back(lease);
+        }
+
+        // Empty page means there are no more leases.
+        if (page.empty()) {
+            break;
+
+        } else {
+            // Record last returned address because it is going to be used
+            // as an argument for the next call.
+            last_address = page[page.size() - 1]->addr_;
+        }
+    }
+
+    // Make sure that we got exactly the number of leases that we earlier
+    // stored in the database.
+    EXPECT_EQ(leases.size(), all_leases.size());
+
+    // Make sure that all leases that we stored in the lease database
+    // have been retrieved.
+    for (Lease6Ptr lease : leases) {
+        bool found = false;
+        for (Lease6Ptr returned_lease : all_leases) {
+            if (lease->addr_ == returned_lease->addr_) {
+                found = true;
+                break;
+            }
+        }
+        EXPECT_TRUE(found) << "lease for address " << lease->addr_.toText()
+            << " was not returned in any of the pages";
+    }
+}
+
 void
 GenericLeaseMgrTest::testGetLeases6DuidIaid() {
     // Get the leases to be used for the test.
index c4112d6a23173074e95a034adf7b4afc940532dd..914bf4e5f4e3636cd6bd9ab5d204ea366b523089 100644 (file)
@@ -215,6 +215,9 @@ public:
     /// @brief Test method which returns all IPv6 leases.
     void testGetLeases6();
 
+    /// @brief Test method which returns range of IPv6 leases with paging.
+    void testGetLeases6Paged();
+
     /// @brief Basic Lease4 Checks
     ///
     /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
index 63daded660413000ef6ea8cc5bc3e51c4c8f6e62..6a88fdce4791f2ac4533089bde2fa0bde62a13e0 100644 (file)
@@ -242,6 +242,35 @@ public:
         return (Lease6Collection());
     }
 
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// This method implements paged browsing of the lease database. The first
+    /// parameter specifies a page size. The second parameter is optional and
+    /// specifies the starting address of the range. This address is excluded
+    /// from the returned range. The IPv6 zero address (default) denotes that
+    /// the first page should be returned. There is no guarantee about the
+    /// order of returned leases.
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of leases by specifying IPv6 zero address as the
+    ///   beginning of the range.
+    /// - Last address of the returned range should be used as a starting
+    ///   address for the next page in the subsequent call.
+    /// - If the number of leases returned is lower than the page size, it
+    ///   indicates that the last page has been retrieved.
+    /// - If there are no leases returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection
+    getLeases6(const asiolink::IOAddress& /* lower_bound_address */,
+               const LeasePageSize& /* page_size */) const {
+        return (Lease6Collection());
+    };
 
     /// @brief Returns expired DHCPv6 leases.
     ///
index 99632a7f61db414319f20e7b1dd4f7e9aeecbbce..59a6b972f4808ef203c92f89690f27b250598aaf 100644 (file)
@@ -954,6 +954,12 @@ TEST_F(MemfileLeaseMgrTest, getLeases6) {
     testGetLeases6();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(MemfileLeaseMgrTest, getLeases6Paged) {
+    startBackend(V6);
+    testGetLeases6Paged();
+}
+
 /// @brief Basic Lease6 Checks
 ///
 /// Checks that the addLease, getLease6 (by address) and deleteLease (with an
index 7cc21eec4a073c0c30f8188bcfdf8f189df86b01..3c4e8a2fbd48ada899dbff5706809ef56e9e4e88 100644 (file)
@@ -375,6 +375,11 @@ TEST_F(MySqlLeaseMgrTest, getLeases6) {
     testGetLeases6();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(MySqlLeaseMgrTest, getLeases6Paged) {
+    testGetLeases6Paged();
+}
+
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
index 364c10638fbbaf5a15ba4bae314ec44c8f945e1f..a444e0a03abe87f68a22b35ea0734dca088d3476 100644 (file)
@@ -364,6 +364,11 @@ TEST_F(PgSqlLeaseMgrTest, getLeases6) {
     testGetLeases6();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(PgSqlLeaseMgrTest, getLeases6Paged) {
+    testGetLeases6Paged();
+}
+
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),