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";
/// @}
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_{
"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,
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();
/// 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.
-// 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
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
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.
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.
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.
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
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.
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 {
/// @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
/// @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.
} // end of anonymous namespace
+using namespace isc::asiolink;
using namespace isc::util;
namespace isc {
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 {
/// @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
#include <time.h>
using namespace isc;
+using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace std;
"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, "
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 {
/// @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.
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
#include <time.h>
using namespace isc;
+using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace std;
"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",
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 {
/// @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.
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
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),
#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>
#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;
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.
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) {
/// @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();
/// @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_;
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
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);
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();
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();