2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-02 06:55:16 +00:00

[5651] Implemented LeaseMgr methods retrieving ranges/pages of IPv4 leases.

This commit is contained in:
Marcin Siodelski
2018-06-25 21:47:20 +02:00
parent d229ba76ef
commit 122bb75a7a
19 changed files with 830 additions and 1 deletions

View File

@@ -217,6 +217,12 @@ public:
static constexpr StatementTag GET_LEASE4_HWADDR = "GET_LEASE4_HWADDR";
// Get lease4 by HW address & subnet ID
static constexpr StatementTag GET_LEASE4_HWADDR_SUBID = "GET_LEASE4_HWADDR_SUBID";
// Get range of lease4 from first lease with a limit
static constexpr StatementTag GET_LEASE4_LIMIT = "GET_LEASE4_LIMIT";
// Get range of lease4 from address with limit (paging)
static constexpr StatementTag GET_LEASE4_PAGE = "GET_LEASE4_PAGE";
// Get range of lease4 between two addresses
static constexpr StatementTag GET_LEASE4_RANGE = "GET_LEASE4_RANGE";
// Get lease4 by subnet ID
static constexpr StatementTag GET_LEASE4_SUBID = "GET_LEASE4_SUBID";
/// @}
@@ -240,6 +246,9 @@ constexpr StatementTag CqlLease4Exchange::GET_LEASE4_CLIENTID;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_CLIENTID_SUBID;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_HWADDR;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_HWADDR_SUBID;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_LIMIT;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_PAGE;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_RANGE;
constexpr StatementTag CqlLease4Exchange::GET_LEASE4_SUBID;
StatementMap CqlLease4Exchange::tagged_statements_{
@@ -349,6 +358,38 @@ StatementMap CqlLease4Exchange::tagged_statements_{
"AND subnet_id = ? "
"ALLOW FILTERING "}},
// Get range of lease4 from first lease with a limit (paging)
{GET_LEASE4_LIMIT,
{GET_LEASE4_LIMIT,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, state "
"FROM lease4 "
"LIMIT ? "
"ALLOW FILTERING "}},
// Get range of lease4 from address with a limit (paging)
{GET_LEASE4_PAGE,
{GET_LEASE4_PAGE,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, state "
"FROM lease4 "
"WHERE TOKEN(address) > TOKEN(?) "
"LIMIT ? "
"ALLOW FILTERING "}},
// Get range of lease4 between two addresses
{GET_LEASE4_RANGE,
{GET_LEASE4_RANGE,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, state "
"FROM lease4 "
"WHERE address >= ? "
"AND address <= ? "
"ALLOW FILTERING "}},
// Gets an IPv4 lease(s) with specified subnet-id
{GET_LEASE4_SUBID,
{GET_LEASE4_SUBID,
@@ -2082,6 +2123,73 @@ CqlLeaseMgr::getLeases4() const {
return (result);
}
Lease4Collection
CqlLeaseMgr::getLeases4(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_PAGE4)
.arg(page_size.page_size_)
.arg(lower_bound_address.toText());
AnyArray data;
cass_int32_t address_data = 0;
if (!lower_bound_address.isV4Zero()) {
address_data = static_cast<cass_int32_t>(lower_bound_address.toUint32());
data.add(&address_data);
}
cass_int32_t page_size_data = static_cast<cass_int32_t>(page_size.page_size_);
data.add(&page_size_data);
// Get the data.
Lease4Collection result;
std::unique_ptr<CqlLease4Exchange> exchange4(new CqlLease4Exchange(dbconn_));
exchange4->getLeaseCollection(lower_bound_address.isV4Zero() ?
CqlLease4Exchange::GET_LEASE4_LIMIT :
CqlLease4Exchange::GET_LEASE4_PAGE,
data, result);
return (result);
}
Lease4Collection
CqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
const IOAddress& upper_bound_address) const {
if (upper_bound_address < lower_bound_address) {
isc_throw(InvalidRange, "upper bound address " << upper_bound_address
<< " is lower than lower bound address " << lower_bound_address);
}
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_ADDR_RANGE4)
.arg(lower_bound_address.toText())
.arg(upper_bound_address.toText());
// Set up the WHERE clause value
AnyArray data;
cass_int32_t lb_address_data = static_cast<cass_int32_t>(lower_bound_address.toUint32());
data.add(&lb_address_data);
cass_int32_t ub_address_data = static_cast<cass_int32_t>(upper_bound_address.toUint32());
data.add(&ub_address_data);
// Get the data.
Lease4Collection result;
std::unique_ptr<CqlLease4Exchange> exchange4(new CqlLease4Exchange(dbconn_));
exchange4->getLeaseCollection(CqlLease4Exchange::GET_LEASE4_RANGE, data, result);
return (result);
}
Lease6Ptr
CqlLeaseMgr::getLease6(Lease::Type lease_type, const IOAddress &addr) const {
std::string addr_data = addr.toText();

View File

@@ -215,6 +215,50 @@ public:
/// this backend.
virtual Lease4Collection getLeases4() const override;
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const override;
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const asiolink::IOAddress& upper_bound_address) const override;
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// For a given address, we assume that there will be only one lease.

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -59,6 +59,14 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Upper bound address is lower than lower bound address while
/// retrieving a range of leases.
class InvalidRange : public Exception {
public:
InvalidRange(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
} // namespace isc
} // namespace dhcp

View File

@@ -279,6 +279,14 @@ A debug message issued when the server is attempting to obtain an IPv6
lease from the Cassandra database for a client with the specified IAID
(Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).
% DHCPSRV_CQL_GET_ADDR_RANGE4 obtaining all IPv4 leases with addresses in range from %1 to %2
A debug message issued when the server is attempting to obtain leases
with addresses in the specified range.
% DHCPSRV_CQL_GET_PAGE4 obtaining at most %1 IPv4 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.
@@ -477,6 +485,14 @@ in the message.
A debug message issued when the server is attempting to obtain all IPv4
leases from the memory file database.
% DHCPSRV_MEMFILE_GET_ADDR_RANGE4 obtaining all IPv4 leases with addresses in range from %1 to %2
A debug message issued when the server is attempting to obtain leases
with addresses in the specified range.
% DHCPSRV_MEMFILE_GET_PAGE4 obtaining at most %1 IPv4 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.
@@ -729,6 +745,14 @@ leases from the MySQL database.
A debug message issued when the server is attempting to obtain an IPv4
lease from the MySQL database for the specified address.
% DHCPSRV_MYSQL_GET_ADDR_RANGE4 obtaining all IPv4 leases with addresses in range from %1 to %2
A debug message issued when the server is attempting to obtain leases
with addresses in the specified range.
% DHCPSRV_MYSQL_GET_PAGE4 obtaining at most %1 IPv4 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.
@@ -905,6 +929,10 @@ lease from the PostgreSQL database for the specified address.
A debug message issued when the server is attempting to obtain an IPv6
lease from the PostgreSQL database for the specified address.
% DHCPSRV_PGSQL_GET_ADDR_RANGE4 obtaining all IPv4 leases with addresses in range from %1 to %2
A debug message issued when the server is attempting to obtain leases
with addresses in the specified range.
% DHCPSRV_PGSQL_GET_CLIENTID obtaining IPv4 leases for client ID %1
A debug message issued when the server is attempting to obtain a set
of IPv4 leases from the PostgreSQL database for a client with the specified
@@ -935,6 +963,10 @@ A debug message issued when the server is attempting to obtain an IPv6
lease from the PostgreSQL database for a client with the specified IAID
(Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).
% DHCPSRV_PGSQL_GET_PAGE4 obtaining at most %1 IPv4 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.

View File

@@ -30,6 +30,19 @@ using namespace std;
namespace isc {
namespace dhcp {
LeasePageSize::LeasePageSize(const size_t page_size)
: page_size_(page_size) {
if (page_size_ == 0) {
isc_throw(OutOfRange, "page size of retrieved leases must not be 0");
}
if (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());
}
}
Lease6Ptr
LeaseMgr::getLease6(Lease::Type type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const {

View File

@@ -64,6 +64,20 @@ namespace dhcp {
/// @brief Pair containing major and minor versions
typedef std::pair<uint32_t, uint32_t> VersionPair;
/// @brief Wraps value holding size of the page with leases.
class LeasePageSize {
public:
/// @brief Constructor.
///
/// @param page_size page size value.
/// @throw OutOfRange if page size is 0 or greater than uint32_t numeric
/// limit.
explicit LeasePageSize(const size_t page_size);
const size_t page_size_; ///< Holds page size.
};
/// @brief Contains a single row of lease statistical data
///
/// The contents of the row consist of a subnet ID, a lease
@@ -350,6 +364,50 @@ public:
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection getLeases4() const = 0;
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const = 0;
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const asiolink::IOAddress& upper_bound_address) const = 0;
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// For a given address, we assume that there will be only one lease.

View File

@@ -38,6 +38,7 @@ const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";
} // end of anonymous namespace
using namespace isc::asiolink;
using namespace isc::util;
namespace isc {
@@ -883,6 +884,59 @@ Memfile_LeaseMgr::getLeases4() const {
return (collection);
}
Lease4Collection
Memfile_LeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE4)
.arg(page_size.page_size_)
.arg(lower_bound_address.toText());
Lease4Collection collection;
const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
Lease4StorageAddressIndex::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(Lease4Ptr(new Lease4(**lease)));
}
return (collection);
}
Lease4Collection
Memfile_LeaseMgr::getLeases4(const IOAddress& lower_bound_address,
const IOAddress& upper_bound_address) const {
// Check if the range boundaries aren't swapped.
if (upper_bound_address < lower_bound_address) {
isc_throw(InvalidRange, "upper bound address " << upper_bound_address
<< " is lower than lower bound address " << lower_bound_address);
}
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_ADDR_RANGE4)
.arg(lower_bound_address.toText())
.arg(upper_bound_address.toText());
Lease4Collection collection;
const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
std::pair<Lease4StorageAddressIndex::const_iterator,
Lease4StorageAddressIndex::const_iterator> l =
std::make_pair(idx.lower_bound(lower_bound_address),
idx.upper_bound(upper_bound_address));
for (auto lease = l.first; lease != l.second; ++lease) {
collection.push_back(Lease4Ptr(new Lease4(**lease)));
}
return (collection);
}
Lease6Ptr
Memfile_LeaseMgr::getLease6(Lease::Type type,
const isc::asiolink::IOAddress& addr) const {

View File

@@ -232,6 +232,50 @@ public:
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection getLeases4() const;
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const;
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const asiolink::IOAddress& upper_bound_address) const;
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// This function returns a copy of the lease. The modification in the

View File

@@ -25,6 +25,7 @@
#include <time.h>
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace std;
@@ -137,6 +138,22 @@ tagged_statements = { {
"state "
"FROM lease4 "
"WHERE hwaddr = ? AND subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_PAGE,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
"state "
"FROM lease4 "
"WHERE address > ? "
"ORDER BY address "
"LIMIT ?"},
{MySqlLeaseMgr::GET_LEASE4_RANGE,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
"state "
"FROM lease4 "
"WHERE address >= ? AND address <= ?"},
{MySqlLeaseMgr::GET_LEASE4_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
@@ -1902,6 +1919,71 @@ MySqlLeaseMgr::getLeases4() const {
return (result);
}
Lease4Collection
MySqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_PAGE4)
.arg(page_size.page_size_)
.arg(lower_bound_address.toText());
// Prepare WHERE clause
MYSQL_BIND inbind[2];
memset(inbind, 0, sizeof(inbind));
// Bind lower bound address
uint32_t lb_address_data = lower_bound_address.toUint32();
inbind[0].buffer_type = MYSQL_TYPE_LONG;
inbind[0].buffer = reinterpret_cast<char*>(&lb_address_data);
inbind[0].is_unsigned = MLM_TRUE;
// 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
Lease4Collection result;
getLeaseCollection(GET_LEASE4_PAGE, inbind, result);
return (result);
}
Lease4Collection
MySqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
const IOAddress& upper_bound_address) const {
if (upper_bound_address < lower_bound_address) {
isc_throw(InvalidRange, "upper bound address " << upper_bound_address
<< " is lower than lower bound address " << lower_bound_address);
}
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_ADDR_RANGE4)
.arg(lower_bound_address.toText())
.arg(upper_bound_address.toText());
// Prepare WHERE clause
MYSQL_BIND inbind[2];
memset(inbind, 0, sizeof(inbind));
// Bind lower bound address as uint32 value
uint32_t lb_address_data = lower_bound_address.toUint32();
inbind[0].buffer_type = MYSQL_TYPE_LONG;
inbind[0].buffer = reinterpret_cast<char*>(&lb_address_data);
inbind[0].is_unsigned = MLM_TRUE;
// Bind upper bound address as uint32 value
uint32_t ub_address_data = upper_bound_address.toUint32();
inbind[1].buffer_type = MYSQL_TYPE_LONG;
inbind[1].buffer = reinterpret_cast<char*>(&ub_address_data);
inbind[1].is_unsigned = MLM_TRUE;
// Get the leases
Lease4Collection result;
getLeaseCollection(GET_LEASE4_RANGE, inbind, result);
return (result);
}
Lease6Ptr
MySqlLeaseMgr::getLease6(Lease::Type lease_type,
const isc::asiolink::IOAddress& addr) const {

View File

@@ -206,6 +206,50 @@ public:
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection getLeases4() const;
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const;
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const asiolink::IOAddress& upper_bound_address) const;
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// For a given address, we assume that there will be only one lease.
@@ -516,6 +560,8 @@ public:
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_EXPIRE, // Get lease4 by expiration.
GET_LEASE6, // Get all IPv6 leases
GET_LEASE6_ADDR, // Get lease6 by address

View File

@@ -21,6 +21,7 @@
#include <time.h>
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace std;
@@ -111,6 +112,28 @@ PgSqlTaggedStatement tagged_statements[] = {
"FROM lease4 "
"WHERE hwaddr = $1 AND subnet_id = $2"},
// GET_LEASE4_PAGE
{ 2, { OID_INT8, OID_INT8 },
"get_lease4_page",
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
"state "
"FROM lease4 "
"WHERE address > $1 "
"ORDER BY address "
"LIMIT $2"},
// GET_LEASE4_RANGE
{ 2, { OID_INT8, OID_INT8 },
"get_lease4_range",
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
"state "
"FROM lease4 "
"WHERE address >= $1 AND address <= $2"},
// GET_LEASE4_SUBID
{ 1, { OID_INT8 },
"get_lease4_subid",
@@ -1294,6 +1317,64 @@ PgSqlLeaseMgr::getLeases4() const {
return (result);
}
Lease4Collection
PgSqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_PAGE4)
.arg(page_size.page_size_)
.arg(lower_bound_address.toText());
// Prepare WHERE clause
PsqlBindArray bind_array;
// Bind lower bound address
std::string lb_address_data = boost::lexical_cast<std::string>
(lower_bound_address.toUint32());
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
Lease4Collection result;
getLeaseCollection(GET_LEASE4_PAGE, bind_array, result);
return (result);
}
Lease4Collection
PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
const IOAddress& upper_bound_address) const {
if (upper_bound_address < lower_bound_address) {
isc_throw(InvalidRange, "upper bound address " << upper_bound_address
<< " is lower than lower bound address " << lower_bound_address);
}
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_ADDR_RANGE4)
.arg(lower_bound_address.toText())
.arg(upper_bound_address.toText());
// Prepare WHERE clause
PsqlBindArray bind_array;
// Bind lower bound address
std::string lb_address_data = boost::lexical_cast<std::string>
(lower_bound_address.toUint32());
bind_array.add(lb_address_data);
// Bind upper bound address
std::string ub_address_data = boost::lexical_cast<std::string>
(upper_bound_address.toUint32());
bind_array.add(ub_address_data);
// Get the leases
Lease4Collection result;
getLeaseCollection(GET_LEASE4_RANGE, bind_array, result);
return (result);
}
Lease6Ptr
PgSqlLeaseMgr::getLease6(Lease::Type lease_type,
const isc::asiolink::IOAddress& addr) const {

View File

@@ -187,6 +187,50 @@ public:
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection getLeases4() const;
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const LeasePageSize& page_size) const;
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& lower_bound_address,
const asiolink::IOAddress& upper_bound_address) const;
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// For a given address, we assume that there will be only one lease.
@@ -483,6 +527,8 @@ 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_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 expired lease4
GET_LEASE6, // Get all IPv6 leases

View File

@@ -587,6 +587,16 @@ TEST_F(CqlLeaseMgrTest, getLeases4) {
testGetLeases4();
}
// Test that a range of IPv4 leases is returned with paging.
TEST_F(CqlLeaseMgrTest, getLeases4Paged) {
testGetLeases4Paged();
}
// Test that a range of IPv4 leases is returmed.
TEST_F(CqlLeaseMgrTest, getLeases4Range) {
testGetLeases4Range();
}
/// @brief Basic Lease4 Checks
///
/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),

View File

@@ -7,6 +7,7 @@
#include <config.h>
#include <asiolink/io_address.h>
#include <exceptions/exceptions.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/lease_mgr_factory.h>
@@ -15,9 +16,11 @@
#include <stats/stats_mgr.h>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <sstream>
using namespace std;
@@ -1245,6 +1248,102 @@ GenericLeaseMgrTest::testGetLeases4() {
ASSERT_EQ(leases.size(), returned.size());
}
void
GenericLeaseMgrTest::testGetLeases4Paged() {
// Get the leases to be used for the test and add to the database.
vector<Lease4Ptr> leases = createLeases4();
for (size_t i = 0; i < leases.size(); ++i) {
EXPECT_TRUE(lmptr_->addLease(leases[i]));
}
Lease4Collection all_leases;
IOAddress last_address = IOAddress("0.0.0.0");
for (auto i = 0; i < 1000; ++i) {
Lease4Collection page = lmptr_->getLeases4(last_address, LeasePageSize(3));
// Collect leases in a common structure. They may be out of order.
for (Lease4Ptr 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 (Lease4Ptr lease : leases) {
bool found = false;
for (Lease4Ptr 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";
}
boost::scoped_ptr<LeasePageSize> lease_page_size;
// The maximum allowed value for the limit is max for uint32_t.
size_t oor = static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1;
EXPECT_THROW(lease_page_size.reset(new LeasePageSize(oor)), OutOfRange);
// Zero page size is illegal too.
EXPECT_THROW(lease_page_size.reset(new LeasePageSize(0)), OutOfRange);
}
void
GenericLeaseMgrTest::testGetLeases4Range() {
// Get the leases to be used for the test and add to the database.
vector<Lease4Ptr> leases = createLeases4();
for (size_t i = 0; i < leases.size(); ++i) {
EXPECT_TRUE(lmptr_->addLease(leases[i]));
}
// All addresses in the specified range should be returned.
Lease4Collection returned = lmptr_->getLeases4(IOAddress("192.0.2.2"),
IOAddress("192.0.2.6"));
EXPECT_EQ(5, returned.size());
// The lower bound address is below the range, so the first two addresses
// in the database should be returned.
returned = lmptr_->getLeases4(IOAddress("192.0.1.0"), IOAddress("192.0.2.1"));
EXPECT_EQ(2, returned.size());
// The lower bound address is the last address in the database, so only this
// address should be returned.
returned = lmptr_->getLeases4(IOAddress("192.0.2.7"), IOAddress("192.0.2.15"));
EXPECT_EQ(1, returned.size());
// The lower bound is below the range and the upper bound is above the range,
// so the whole range should be returned.
returned = lmptr_->getLeases4(IOAddress("192.0.1.7"), IOAddress("192.0.2.15"));
EXPECT_EQ(8, returned.size());
// No addresses should be returned because our desired range does not
// overlap with leases in the database.
returned = lmptr_->getLeases4(IOAddress("192.0.2.8"), IOAddress("192.0.2.15"));
EXPECT_TRUE(returned.empty());
// Swapping the lower bound and upper bound should cause an error.
EXPECT_THROW(lmptr_->getLeases4(IOAddress("192.0.2.8"), IOAddress("192.0.2.1")),
InvalidRange);
}
void
GenericLeaseMgrTest::testGetLeases6SubnetId() {
// Get the leases to be used for the test and add to the database.
@@ -2860,6 +2959,17 @@ LeaseMgrDbLostCallbackTest::testDbLostCallback() {
EXPECT_TRUE(callback_called_);
}
void
GenericLeaseMgrTest::checkLeaseRange(const Lease4Collection& returned,
const std::vector<std::string>& expected_addresses) {
ASSERT_EQ(expected_addresses.size(), returned.size());
for (auto a = returned.cbegin(); a != returned.cend(); ++a) {
EXPECT_EQ(expected_addresses[std::distance(returned.cbegin(), a)],
(*a)->addr_.toText());
}
}
void
GenericLeaseMgrTest::checkQueryAgainstRowSet(const LeaseStatsQueryPtr& query,
const RowSet& expected_rows) {

View File

@@ -203,6 +203,12 @@ public:
/// @brief Test method which returns all IPv4 leases.
void testGetLeases4();
/// @brief Test method which returns range of IPv4 leases with paging.
void testGetLeases4Paged();
/// @brief Test method which returns range of IPv4 leases.
void testGetLeases4Range();
/// @brief Test method which returns all IPv6 leases for Subnet ID.
void testGetLeases6SubnetId();
@@ -426,6 +432,13 @@ public:
/// @param row_set - set of rows expected to be found in the query rows
void checkQueryAgainstRowSet(const LeaseStatsQueryPtr& qry, const RowSet& row_set);
/// @brief Checks if specified range of leases was returned.
///
/// @param returned collection of leases returned.
/// @param expected_addresses ordered collection of expected addresses.
void checkLeaseRange(const Lease4Collection& returned,
const std::vector<std::string>& expected_addresses);
/// @brief String forms of IPv4 addresses
std::vector<std::string> straddress4_;

View File

@@ -145,6 +145,54 @@ public:
return (Lease4Collection());
}
/// @brief Returns range of IPv4 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 IPv4 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 IPv4 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 IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& /* lower_bound_address */,
const LeasePageSize& /* page_size */) const {
return (Lease4Collection());
}
/// @brief Returns a range of IPv4 leases.
///
/// Returned leases are ordered by IPv4 addresses.
///
/// @param lower_bound_address IPv4 address used as a lower bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
/// @param upper_bound_address IPv4 address used as an upper bound for the
/// returned range. The lease for this address is included in the returned
/// range if the lease exists.
///
/// @return Lease collection (may be empty if no IPv4 lease found).
virtual Lease4Collection
getLeases4(const asiolink::IOAddress& /* lower_bound_address */,
const asiolink::IOAddress& /* upper_bound_address */) const {
return (Lease4Collection());
}
/// @brief Returns existing IPv6 lease for a given IPv6 address.
///
/// @param addr address of the searched lease

View File

@@ -930,6 +930,18 @@ TEST_F(MemfileLeaseMgrTest, getLeases4) {
testGetLeases4();
}
// Test that a range of IPv4 leases is returned with paging.
TEST_F(MemfileLeaseMgrTest, getLeases4Paged) {
startBackend(V4);
testGetLeases4Paged();
}
// Test that a range of IPv4 leases is returmed.
TEST_F(MemfileLeaseMgrTest, getLeases4Range) {
startBackend(V4);
testGetLeases4Range();
}
// This test checks that all IPv6 leases for a specified subnet id are returned.
TEST_F(MemfileLeaseMgrTest, getLeases6SubnetId) {
startBackend(V6);

View File

@@ -355,6 +355,16 @@ TEST_F(MySqlLeaseMgrTest, getLeases4) {
testGetLeases4();
}
// Test that a range of IPv4 leases is returned with paging.
TEST_F(MySqlLeaseMgrTest, getLeases4Paged) {
testGetLeases4Paged();
}
// Test that a range of IPv4 leases is returmed.
TEST_F(MySqlLeaseMgrTest, getLeases4Range) {
testGetLeases4Range();
}
// This test checks that all IPv6 leases for a specified subnet id are returned.
TEST_F(MySqlLeaseMgrTest, getLeases6SubnetId) {
testGetLeases6SubnetId();

View File

@@ -344,6 +344,16 @@ TEST_F(PgSqlLeaseMgrTest, getLeases4) {
testGetLeases4();
}
// Test that a range of IPv4 leases is returned with paging.
TEST_F(PgSqlLeaseMgrTest, getLeases4Paged) {
testGetLeases4Paged();
}
// Test that a range of IPv4 leases is returmed.
TEST_F(PgSqlLeaseMgrTest, getLeases4Range) {
testGetLeases4Range();
}
// This test checks that all IPv6 leases for a specified subnet id are returned.
TEST_F(PgSqlLeaseMgrTest, getLeases6SubnetId) {
testGetLeases6SubnetId();