A debug message issued when the server is attempting to obtain a page
of leases beginning with the specified address.
+% DHCPSRV_MYSQL_GET_RELAYID4 obtaining at most %1 IPv4 leases starting from address %2 with relay id %3 and cltt between %4 and %5
+A debug message issued when the server is attempting to obtain a page of
+IPv4 leases beginning with the specified address with a relay id and client
+transaction time between start and end dates.
+
+% DHCPSRV_MYSQL_GET_REMOTEID4 obtaining at most %1 IPv4 leases starting from address %2 with remote id %3 and cltt between %4 and %5
+A debug message issued when the server is attempting to obtain a page of
+IPv4 leases beginning with the specified address with a remote id and client
+transaction time between start and end dates.
+
% DHCPSRV_MYSQL_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 MySQL database.
A debug message issued when the server is attempting to obtain a page
of leases beginning with the specified address.
+% DHCPSRV_PGSQL_GET_RELAYID4 obtaining at most %1 IPv4 leases starting from address %2 with relay id %3 and cltt between %4 and %5
+A debug message issued when the server is attempting to obtain a page of
+IPv4 leases beginning with the specified address with a relay id and client
+transaction time between start and end dates.
+
+% DHCPSRV_PGSQL_GET_REMOTEID4 obtaining at most %1 IPv4 leases starting from address %2 with remote id %3 and cltt between %4 and %5
+A debug message issued when the server is attempting to obtain a page of
+IPv4 leases beginning with the specified address with a remote id and client
+transaction time between start and end dates.
+
% 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.
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4"},
{MySqlLeaseMgr::GET_LEASE4_ADDR,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE address = ?"},
{MySqlLeaseMgr::GET_LEASE4_CLIENTID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE client_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE client_id = ? AND subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_HWADDR,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE hwaddr = ?"},
{MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"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, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE address > ? "
"ORDER BY address "
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_HOSTNAME,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE hostname = ?"},
{MySqlLeaseMgr::GET_LEASE4_EXPIRE,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE state != ? "
"AND valid_lifetime != 4294967295 "
"AND expire < ? "
"ORDER BY expire ASC "
"LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_RELAYID,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = ? and address > ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_RELAYID_QST,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " >= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_RELAYID_QSET,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " >= ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " <= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_RELAYID_QET,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " <= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_REMOTEID,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = ? and address > ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QST,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " >= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QSET,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " >= ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " <= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
+ {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QET,
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, expire, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = ? and address > ? "
+ " and UNIX_TIMESTAMP(expire) - IF"
+ "(valid_lifetime = 4294967295, 0, valid_lifetime)"
+ " <= ? "
+ "ORDER BY address "
+ "LIMIT ?"},
{MySqlLeaseMgr::GET_LEASE6,
"SELECT address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+ "state, user_context, relay_id, remote_id) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
{MySqlLeaseMgr::INSERT_LEASE6,
"INSERT INTO lease6(address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"client_id = ?, valid_lifetime = ?, expire = ?, "
"subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
"hostname = ?, "
- "state = ?, user_context = ? "
+ "state = ?, user_context = ?, "
+ "relay_id = ?, remote_id = ? "
"WHERE address = ? AND expire = ?"},
{MySqlLeaseMgr::UPDATE_LEASE6,
"UPDATE lease6 SET address = ?, duid = ?, "
class MySqlLease4Exchange : public MySqlLeaseExchange {
/// @brief Set number of database columns for this lease structure
- static const size_t LEASE_COLUMNS = 11;
+ static const size_t LEASE_COLUMNS = 13;
public:
subnet_id_(0), valid_lifetime_(0),
fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
state_(0), user_context_length_(0),
- user_context_null_(MLM_FALSE) {
+ user_context_null_(MLM_FALSE),
+ relay_id_null_(MLM_FALSE),
+ remote_id_null_(MLM_FALSE) {
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
memset(user_context_, 0, sizeof(user_context_));
+ memset(relay_id_buffer_, 0, sizeof(relay_id_buffer_));
+ memset(remote_id_buffer_, 0, sizeof(remote_id_buffer_));
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
// Set the column names (for error messages)
columns_[8] = "hostname";
columns_[9] = "state";
columns_[10] = "user_context";
- BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
+ columns_[11] = "relay_id";
+ columns_[12] = "remote_id";
+ BOOST_STATIC_ASSERT(12 < LEASE_COLUMNS);
}
/// @brief Create MYSQL_BIND objects for Lease4 Pointer
bind_[10].buffer_type = MYSQL_TYPE_NULL;
}
+ // relay_id: varbinary(128)
+ relay_id_ = lease_->relay_id_;
+ if (!relay_id_.empty()) {
+ bind_[11].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[11].buffer = reinterpret_cast<char*>(&relay_id_[0]);
+ relay_id_length_ = relay_id_.size();
+ bind_[11].buffer_length = relay_id_length_;
+ bind_[11].length = &relay_id_length_;
+ } else {
+ bind_[11].buffer_type = MYSQL_TYPE_NULL;
+ relay_id_null_ = MLM_TRUE;
+ bind_[11].buffer = NULL;
+ bind_[11].is_null = &relay_id_null_;
+ }
+
+ // remote_id: varbinary(128)
+ remote_id_ = lease_->remote_id_;
+ if (!remote_id_.empty()) {
+ bind_[12].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[12].buffer = reinterpret_cast<char*>(&remote_id_[0]);
+ remote_id_length_ = remote_id_.size();
+ bind_[12].buffer_length = remote_id_length_;
+ bind_[12].length = &remote_id_length_;
+ } else {
+ bind_[12].buffer_type = MYSQL_TYPE_NULL;
+ remote_id_null_ = MLM_TRUE;
+ bind_[12].buffer = NULL;
+ bind_[12].is_null = &remote_id_null_;
+ }
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
bind_[10].length = &user_context_length_;
bind_[10].is_null = &user_context_null_;
+ // relay_id: varbinary(128)
+ relay_id_length_ = sizeof(relay_id_buffer_);
+ bind_[11].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[11].buffer = reinterpret_cast<char*>(relay_id_buffer_);
+ bind_[11].buffer_length = relay_id_length_;
+ bind_[11].length = &relay_id_length_;
+ bind_[11].is_null = &relay_id_null_;
+
+ // remote_id: varbinary(128)
+ remote_id_length_ = sizeof(remote_id_buffer_);
+ bind_[12].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[12].buffer = reinterpret_cast<char*>(remote_id_buffer_);
+ bind_[12].buffer_length = remote_id_length_;
+ bind_[12].length = &remote_id_length_;
+ bind_[12].is_null = &remote_id_null_;
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
lease->setContext(ctx);
}
+ // Set relay id if it was set.
+ if (relay_id_null_ == MLM_FALSE) {
+ lease->relay_id_.assign(relay_id_buffer_,
+ relay_id_buffer_ + relay_id_length_);
+ }
+
+ // Set remote id if it was set.
+ if (remote_id_null_ == MLM_FALSE) {
+ lease->remote_id_.assign(remote_id_buffer_,
+ remote_id_buffer_ + remote_id_length_);
+ }
+
return (lease);
}
char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context
unsigned long user_context_length_; ///< Length of user context
my_bool user_context_null_; ///< Used when user context is null
+ std::vector<uint8_t> relay_id_; ///< Relay id
+ uint8_t relay_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Relay id buffer
+ unsigned long relay_id_length_; ///< Relay id length
+ my_bool relay_id_null_; ///< Used when Relay id is null
+ std::vector<uint8_t> remote_id_; ///< Remote id
+ uint8_t remote_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Remote id buffer
+ unsigned long remote_id_length_; ///< Remote id length
+ my_bool remote_id_null_; ///< Used when Remote id is null
};
/// @brief Exchange MySQL and Lease6 Data
inbind[0].is_unsigned = MLM_TRUE;
// Bind page size value
- size_t* ps = const_cast<size_t*>(&page_size.page_size_);
+ uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
inbind[1].buffer_type = MYSQL_TYPE_LONG;
- inbind[1].buffer = reinterpret_cast<char*>(ps);
+ inbind[1].buffer = reinterpret_cast<char*>(&ps);
inbind[1].is_unsigned = MLM_TRUE;
// Get the leases
inbind[0].length = &lb_address_data_size;
// Bind page size value
- size_t* ps = const_cast<size_t*>(&page_size.page_size_);
+ uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
inbind[1].buffer_type = MYSQL_TYPE_LONG;
- inbind[1].buffer = reinterpret_cast<char*>(ps);
+ inbind[1].buffer = reinterpret_cast<char*>(&ps);
inbind[1].is_unsigned = MLM_TRUE;
// Get the leases
isc_throw(NotImplemented, "MySqlLeaseMgr::addRemoteId6 not implemented");
}
+namespace {
+
+std::string
+idToText(const OptionBuffer& id) {
+ std::stringstream tmp;
+ tmp << std::hex;
+ bool delim = false;
+ for (std::vector<uint8_t>::const_iterator it = id.begin();
+ it != id.end(); ++it) {
+ if (delim) {
+ tmp << ":";
+ }
+ tmp << std::setw(2) << std::setfill('0')
+ << static_cast<unsigned int>(*it);
+ delim = true;
+ }
+ return (tmp.str());
+}
+
+} // anonymous namespace
+
Lease4Collection
-MySqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& /* relay_id */,
- const IOAddress& /* lower_bound_address */,
- const LeasePageSize& /* page_size */,
- const time_t& /* qry_start_time = 0 */,
- const time_t& /* qry_end_time = 0 */) {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases4ByRelayId not implemented");
+MySqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& relay_id,
+ const IOAddress& lower_bound_address,
+ const LeasePageSize& page_size,
+ const time_t& qry_start_time /* = 0 */,
+ const time_t& qry_end_time /* = 0 */) {
+ // Expecting IPv4 address.
+ if (!lower_bound_address.isV4()) {
+ isc_throw(InvalidAddressFamily, "expected IPv4 address while "
+ "retrieving leases from the lease database, got "
+ << lower_bound_address);
+ }
+
+ // Catch 2038 bug with 32 bit time_t.
+ if ((qry_start_time < 0) || (qry_end_time < 0)) {
+ isc_throw(BadValue, "negative time value");
+ }
+
+ bool have_qst = (qry_start_time > 0);
+ bool have_qet = (qry_end_time > 0);
+
+ // Start time must be before end time.
+ if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
+ isc_throw(BadValue, "start time must be before end time");
+ }
+
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+ DHCPSRV_MYSQL_GET_RELAYID4)
+ .arg(page_size.page_size_)
+ .arg(lower_bound_address.toText())
+ .arg(idToText(relay_id))
+ .arg(qry_start_time)
+ .arg(qry_end_time);
+
+ // Prepare WHERE clause
+ size_t bindings = 3;
+ if (have_qst) {
+ ++bindings;
+ }
+ if (have_qet) {
+ ++bindings;
+ }
+ MYSQL_BIND inbind[bindings];
+ memset(inbind, 0, sizeof(inbind));
+
+ std::vector<uint8_t> relay_id_data = relay_id;
+ unsigned long relay_id_length = relay_id.size();
+
+ // If the relay id happens to be empty, we have to create a
+ // 1 byte dummy buffer and pass it to the binding.
+ if (relay_id_data.empty()) {
+ relay_id_data.resize(1);
+ }
+
+ // Bind relay id
+ inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+ inbind[0].buffer = reinterpret_cast<char*>(&relay_id_data[0]);
+ inbind[0].buffer_length = relay_id_length;
+ inbind[0].length = &relay_id_length;
+
+ // Bind lower bound address
+ uint32_t lb_address_data = lower_bound_address.toUint32();
+ inbind[1].buffer_type = MYSQL_TYPE_LONG;
+ inbind[1].buffer = reinterpret_cast<char*>(&lb_address_data);
+ inbind[1].is_unsigned = MLM_TRUE;
+
+ size_t index = 2;
+ // Bind query start time.
+ uint32_t start_time = static_cast<uint32_t>(qry_start_time);
+ if (have_qst) {
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&start_time);
+ inbind[index].is_unsigned = MLM_TRUE;
+ ++index;
+ }
+
+ // Bind query end time.
+ uint32_t end_time = static_cast<uint32_t>(qry_end_time);
+ if (have_qet) {
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&end_time);
+ inbind[index].is_unsigned = MLM_TRUE;
+ ++index;
+ }
+
+ // Bind page size value
+ uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&ps);
+ inbind[index].is_unsigned = MLM_TRUE;
+
+ StatementIndex stindex = GET_LEASE4_RELAYID;
+ if (have_qst && !have_qet) {
+ stindex = GET_LEASE4_RELAYID_QST;
+ } else if (have_qst && have_qet) {
+ stindex = GET_LEASE4_RELAYID_QSET;
+ } else if (!have_qst && have_qet) {
+ stindex = GET_LEASE4_RELAYID_QET;
+ }
+
+ // Get the leases
+ Lease4Collection result;
+
+ // Get a context
+ MySqlLeaseContextAlloc get_context(*this);
+ MySqlLeaseContextPtr ctx = get_context.ctx_;
+
+ getLeaseCollection(ctx, stindex, inbind, result);
+
+ return (result);
}
Lease4Collection
-MySqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& /* remote_id */,
- const IOAddress& /* lower_bound_address */,
- const LeasePageSize& /* page_size */,
- const time_t& /* qry_start_time = 0 */,
- const time_t& /* qry_end_time = 0 */) {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases4ByRemoteId not implemented");
+MySqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& remote_id,
+ const IOAddress& lower_bound_address,
+ const LeasePageSize& page_size,
+ const time_t& qry_start_time /* = 0 */,
+ const time_t& qry_end_time /* = 0 */) {
+ // Expecting IPv4 address.
+ if (!lower_bound_address.isV4()) {
+ isc_throw(InvalidAddressFamily, "expected IPv4 address while "
+ "retrieving leases from the lease database, got "
+ << lower_bound_address);
+ }
+
+ // Catch 2038 bug with 32 bit time_t.
+ if ((qry_start_time < 0) || (qry_end_time < 0)) {
+ isc_throw(BadValue, "negative time value");
+ }
+
+ bool have_qst = (qry_start_time > 0);
+ bool have_qet = (qry_end_time > 0);
+
+ // Start time must be before end time.
+ if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
+ isc_throw(BadValue, "start time must be before end time");
+ }
+
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+ DHCPSRV_MYSQL_GET_REMOTEID4)
+ .arg(page_size.page_size_)
+ .arg(lower_bound_address.toText())
+ .arg(idToText(remote_id))
+ .arg(qry_start_time)
+ .arg(qry_end_time);
+
+ // Prepare WHERE clause
+ size_t bindings = 3;
+ if (have_qst) {
+ ++bindings;
+ }
+ if (have_qet) {
+ ++bindings;
+ }
+ MYSQL_BIND inbind[bindings];
+ memset(inbind, 0, sizeof(inbind));
+
+ std::vector<uint8_t> remote_id_data = remote_id;
+ unsigned long remote_id_length = remote_id.size();
+
+ // If the remote id happens to be empty, we have to create a
+ // 1 byte dummy buffer and pass it to the binding.
+ if (remote_id_data.empty()) {
+ remote_id_data.resize(1);
+ }
+
+ // Bind remote id
+ inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+ inbind[0].buffer = reinterpret_cast<char*>(&remote_id_data[0]);
+ inbind[0].buffer_length = remote_id_length;
+ inbind[0].length = &remote_id_length;
+
+ // Bind lower bound address
+ uint32_t lb_address_data = lower_bound_address.toUint32();
+ inbind[1].buffer_type = MYSQL_TYPE_LONG;
+ inbind[1].buffer = reinterpret_cast<char*>(&lb_address_data);
+ inbind[1].is_unsigned = MLM_TRUE;
+
+ size_t index = 2;
+ // Bind query start time.
+ uint32_t start_time = static_cast<uint32_t>(qry_start_time);
+ if (have_qst) {
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&start_time);
+ inbind[index].is_unsigned = MLM_TRUE;
+ ++index;
+ }
+
+ // Bind query end time.
+ uint32_t end_time = static_cast<uint32_t>(qry_end_time);
+ if (have_qet) {
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&end_time);
+ inbind[index].is_unsigned = MLM_TRUE;
+ ++index;
+ }
+
+ // Bind page size value
+ uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
+ inbind[index].buffer_type = MYSQL_TYPE_LONG;
+ inbind[index].buffer = reinterpret_cast<char*>(&ps);
+ inbind[index].is_unsigned = MLM_TRUE;
+
+ StatementIndex stindex = GET_LEASE4_REMOTEID;
+ if (have_qst && !have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QST;
+ } else if (have_qst && have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QSET;
+ } else if (!have_qst && have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QET;
+ }
+
+ // Get the leases
+ Lease4Collection result;
+
+ // Get a context
+ MySqlLeaseContextAlloc get_context(*this);
+ MySqlLeaseContextPtr ctx = get_context.ctx_;
+
+ getLeaseCollection(ctx, stindex, inbind, result);
+
+ return (result);
}
Lease6Collection
GET_LEASE4_SUBID, // Get IPv4 leases by subnet ID
GET_LEASE4_HOSTNAME, // Get IPv4 leases by hostname
GET_LEASE4_EXPIRE, // Get lease4 by expiration.
+ GET_LEASE4_RELAYID, // Get page of lease by relay ID.
+ GET_LEASE4_RELAYID_QST, // Get page of leases by relay ID and query start time.
+ GET_LEASE4_RELAYID_QSET, // Get page of leases by relay ID and query start and end times.
+ GET_LEASE4_RELAYID_QET, // Get page of leases by relay ID and query end time.
+ GET_LEASE4_REMOTEID, // Get page of lease by remote ID.
+ GET_LEASE4_REMOTEID_QST, // Get page of leases by remote ID and query start time.
+ GET_LEASE4_REMOTEID_QSET, // Get page of leases by remote ID and query start and end times.
+ GET_LEASE4_REMOTEID_QET, // Get page of leases by remote ID and query end time.
GET_LEASE6, // Get all IPv6 leases
GET_LEASE6_ADDR, // Get lease6 by address
GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4"},
// GET_LEASE4_ADDR
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE address = $1"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE client_id = $1"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE client_id = $1 AND subnet_id = $2"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE hwaddr = $1"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE hwaddr = $1 AND subnet_id = $2"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE address > $1 "
"ORDER BY address "
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE subnet_id = $1"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE lower(hostname) = $1"},
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context "
+ "state, user_context, relay_id, remote_id "
"FROM lease4 "
"WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 "
"ORDER BY expire "
"LIMIT $3"},
+ // GET_LEASE4_RELAYID
+ { 3, { OID_BYTEA, OID_INT8, OID_INT8 },
+ "get_lease4_relayid",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = $1 and address > $2 "
+ "ORDER BY address "
+ "LIMIT $3"},
+
+ // GET_LEASE4_RELAYID_QST
+ { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_relayid_qst",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) >= $3 "
+ "ORDER BY address "
+ "LIMIT $4"},
+
+ // GET_LEASE4_RELAYID_QSET
+ { 5, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_relayid_qset",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) >= $3 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) <= $4 "
+ "ORDER BY address "
+ "LIMIT $5"},
+
+ // GET_LEASE4_RELAYID_QET
+ { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_relayid_qet",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE relay_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) <= $3 "
+ "ORDER BY address "
+ "LIMIT $4"},
+
+ // GET_LEASE4_REMOTEID
+ { 3, { OID_BYTEA, OID_INT8, OID_INT8 },
+ "get_lease4_remoteid",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = $1 and address > $2 "
+ "ORDER BY address "
+ "LIMIT $3"},
+
+ // GET_LEASE4_REMOTEID_QST
+ { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_remoteid_qst",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) >= $3 "
+ "ORDER BY address "
+ "LIMIT $4"},
+
+ // GET_LEASE4_REMOTEID_QSET
+ { 5, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_remoteid_qset",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) >= $3 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) <= $4 "
+ "ORDER BY address "
+ "LIMIT $5"},
+
+ // GET_LEASE4_REMOTEID_QET
+ { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
+ "get_lease4_remoteid_qet",
+ "SELECT address, hwaddr, client_id, "
+ "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state, user_context, relay_id, remote_id "
+ "FROM lease4 "
+ "WHERE remote_id = $1 and address > $2 "
+ "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
+ "THEN 0 ELSE valid_lifetime END) <= $3 "
+ "ORDER BY address "
+ "LIMIT $4"},
+
// GET_LEASE6
{ 0, { OID_NONE },
"get_lease6",
"LIMIT $3"},
// INSERT_LEASE4
- { 11, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
- OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT },
+ { 13, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_BYTEA,
+ OID_BYTEA },
"insert_lease4",
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
- "state, user_context) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"},
+ "state, user_context, relay_id, remote_id) "
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"},
// INSERT_LEASE6
{ 17, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"},
// UPDATE_LEASE4
- { 13, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
- OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_INT8, OID_TIMESTAMP },
+ { 15, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_BYTEA,
+ OID_BYTEA, OID_INT8, OID_TIMESTAMP },
"update_lease4",
"UPDATE lease4 SET address = $1, hwaddr = $2, "
"client_id = $3, valid_lifetime = $4, expire = $5, "
"subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
- "state = $10, user_context = $11 "
- "WHERE address = $12 AND expire = $13"},
+ "state = $10, user_context = $11, relay_id = $12, remote_id = $13 "
+ "WHERE address = $14 AND expire = $15"},
// UPDATE_LEASE6
{ 19, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
static const size_t HOSTNAME_COL = 8;
static const size_t STATE_COL = 9;
static const size_t USER_CONTEXT_COL = 10;
+ static const size_t RELAY_ID_COL = 11;
+ static const size_t REMOTE_ID_COL = 12;
/// @brief Number of columns in the table holding DHCPv4 leases.
- static const size_t LEASE_COLUMNS = 11;
+ static const size_t LEASE_COLUMNS = 13;
public:
/// @brief Constructor
PgSqlLease4Exchange()
- : lease_(), addr4_(0), client_id_length_(0) {
+ : lease_(), addr4_(0), client_id_length_(0),
+ relay_id_length_(0), remote_id_length_(0) {
BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
+ memset(relay_id_buffer_, 0, sizeof(relay_id_buffer_));
+ memset(remote_id_buffer_, 0, sizeof(remote_id_buffer_));
// Set the column names (for error messages)
columns_.push_back("address");
columns_.push_back("hostname");
columns_.push_back("state");
columns_.push_back("user_context");
+ columns_.push_back("relay_id");
+ columns_.push_back("remote_id");
}
/// @brief Creates the bind array for sending Lease4 data to the database.
user_context_ = "";
}
bind_array.add(user_context_);
+
+ if (!lease->relay_id_.empty()) {
+ bind_array.add(lease->relay_id_);
+ } else {
+ bind_array.addNull();
+ }
+
+ if (!lease->remote_id_.empty()) {
+ bind_array.add(lease->remote_id_);
+ } else {
+ bind_array.addNull();
+ }
+
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
"Could not create bind array from Lease4: "
}
}
+ convertFromBytea(r, row, RELAY_ID_COL, relay_id_buffer_,
+ sizeof(relay_id_buffer_), relay_id_length_);
+
+ convertFromBytea(r, row, REMOTE_ID_COL, remote_id_buffer_,
+ sizeof(remote_id_buffer_), remote_id_length_);
+
Lease4Ptr result(boost::make_shared<Lease4>(addr4_, hwaddr,
client_id_buffer_,
client_id_length_,
result->setContext(ctx);
}
+ if (relay_id_length_) {
+ result->relay_id_.assign(relay_id_buffer_,
+ relay_id_buffer_ + relay_id_length_);
+ }
+
+ if (remote_id_length_) {
+ result->remote_id_.assign(remote_id_buffer_,
+ remote_id_buffer_ + remote_id_length_);
+ }
+
return (result);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
uint32_t addr4_;
size_t client_id_length_;
uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
+ size_t relay_id_length_;
+ uint8_t relay_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
+ size_t remote_id_length_;
+ uint8_t remote_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
};
/// @brief Supports exchanging IPv6 leases with PostgreSQL.
isc_throw(NotImplemented, "PgSqlLeaseMgr::addRemoteId6 not implemented");
}
+namespace {
+
+std::string
+idToText(const OptionBuffer& id) {
+ std::stringstream tmp;
+ tmp << std::hex;
+ bool delim = false;
+ for (std::vector<uint8_t>::const_iterator it = id.begin();
+ it != id.end(); ++it) {
+ if (delim) {
+ tmp << ":";
+ }
+ tmp << std::setw(2) << std::setfill('0')
+ << static_cast<unsigned int>(*it);
+ delim = true;
+ }
+ return (tmp.str());
+}
+
+} // anonymous namespace
+
Lease4Collection
-PgSqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& /* relay_id */,
- const IOAddress& /* lower_bound_address */,
- const LeasePageSize& /* page_size */,
- const time_t& /* qry_start_time = 0 */,
- const time_t& /* qry_end_time = 0 */) {
- isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRelayId not implemented");
+PgSqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& relay_id,
+ const IOAddress& lower_bound_address,
+ const LeasePageSize& page_size,
+ const time_t& qry_start_time /* = 0 */,
+ const time_t& qry_end_time /* = 0 */) {
+ // Expecting IPv4 address.
+ if (!lower_bound_address.isV4()) {
+ isc_throw(InvalidAddressFamily, "expected IPv4 address while "
+ "retrieving leases from the lease database, got "
+ << lower_bound_address);
+ }
+
+ // Catch 2038 bug with 32 bit time_t.
+ if ((qry_start_time < 0) || (qry_end_time < 0)) {
+ isc_throw(BadValue, "negative time value");
+ }
+
+ bool have_qst = (qry_start_time > 0);
+ bool have_qet = (qry_end_time > 0);
+
+ // Start time must be before end time.
+ if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
+ isc_throw(BadValue, "start time must be before end time");
+ }
+
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+ DHCPSRV_PGSQL_GET_RELAYID4)
+ .arg(page_size.page_size_)
+ .arg(lower_bound_address.toText())
+ .arg(idToText(relay_id))
+ .arg(qry_start_time)
+ .arg(qry_end_time);
+
+ // Prepare WHERE clause
+ PsqlBindArray bind_array;
+
+ // Bind relay id
+ if (!relay_id.empty()) {
+ bind_array.add(relay_id);
+ } else {
+ bind_array.add("");
+ }
+
+ // 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 query start time.
+ std::string start_time_str;
+ if (have_qst) {
+ start_time_str = boost::lexical_cast<std::string>(qry_start_time);
+ bind_array.add(start_time_str);
+ }
+
+ // Bind query end time.
+ std::string end_time_str;
+ if (have_qet) {
+ end_time_str = boost::lexical_cast<std::string>(qry_end_time);
+ bind_array.add(end_time_str);
+ }
+
+ // Bind page size value
+ std::string page_size_data =
+ boost::lexical_cast<std::string>(page_size.page_size_);
+ bind_array.add(page_size_data);
+
+ StatementIndex stindex = GET_LEASE4_RELAYID;
+ if (have_qst && !have_qet) {
+ stindex = GET_LEASE4_RELAYID_QST;
+ } else if (have_qst && have_qet) {
+ stindex = GET_LEASE4_RELAYID_QSET;
+ } else if (!have_qst && have_qet) {
+ stindex = GET_LEASE4_RELAYID_QET;
+ }
+
+ // Get the leases
+ Lease4Collection result;
+
+ // Get a context
+ PgSqlLeaseContextAlloc get_context(*this);
+ PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+ getLeaseCollection(ctx, stindex, bind_array, result);
+
+ return (result);
}
Lease4Collection
-PgSqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& /* remote_id */,
- const IOAddress& /* lower_bound_address */,
- const LeasePageSize& /* page_size */,
- const time_t& /* qry_start_time = 0 */,
- const time_t& /* qry_end_time = 0 */) {
- isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRemoteId not implemented");
+PgSqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& remote_id,
+ const IOAddress& lower_bound_address,
+ const LeasePageSize& page_size,
+ const time_t& qry_start_time /* = 0 */,
+ const time_t& qry_end_time /* = 0 */) {
+ // Expecting IPv4 address.
+ if (!lower_bound_address.isV4()) {
+ isc_throw(InvalidAddressFamily, "expected IPv4 address while "
+ "retrieving leases from the lease database, got "
+ << lower_bound_address);
+ }
+
+ // Catch 2038 bug with 32 bit time_t.
+ if ((qry_start_time < 0) || (qry_end_time < 0)) {
+ isc_throw(BadValue, "negative time value");
+ }
+
+ bool have_qst = (qry_start_time > 0);
+ bool have_qet = (qry_end_time > 0);
+
+ // Start time must be before end time.
+ if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
+ isc_throw(BadValue, "start time must be before end time");
+ }
+
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+ DHCPSRV_PGSQL_GET_REMOTEID4)
+ .arg(page_size.page_size_)
+ .arg(lower_bound_address.toText())
+ .arg(idToText(remote_id))
+ .arg(qry_start_time)
+ .arg(qry_end_time);
+
+ // Prepare WHERE clause
+ PsqlBindArray bind_array;
+
+ // Bind remote id
+ if (!remote_id.empty()) {
+ bind_array.add(remote_id);
+ } else {
+ bind_array.add("");
+ }
+
+ // 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 query start time.
+ std::string start_time_str;
+ if (have_qst) {
+ start_time_str = boost::lexical_cast<std::string>(qry_start_time);
+ bind_array.add(start_time_str);
+ }
+
+ // Bind query end time.
+ std::string end_time_str;
+ if (have_qet) {
+ end_time_str = boost::lexical_cast<std::string>(qry_end_time);
+ bind_array.add(end_time_str);
+ }
+
+ // Bind page size value
+ std::string page_size_data =
+ boost::lexical_cast<std::string>(page_size.page_size_);
+ bind_array.add(page_size_data);
+
+ StatementIndex stindex = GET_LEASE4_REMOTEID;
+ if (have_qst && !have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QST;
+ } else if (have_qst && have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QSET;
+ } else if (!have_qst && have_qet) {
+ stindex = GET_LEASE4_REMOTEID_QET;
+ }
+
+ // Get the leases
+ Lease4Collection result;
+
+ // Get a context
+ PgSqlLeaseContextAlloc get_context(*this);
+ PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+ getLeaseCollection(ctx, stindex, bind_array, result);
+
+ return (result);
}
Lease6Collection
GET_LEASE4_SUBID, // Get IPv4 leases by subnet ID
GET_LEASE4_HOSTNAME, // Get IPv4 leases by hostname
GET_LEASE4_EXPIRE, // Get lease4 by expiration.
+ GET_LEASE4_RELAYID, // Get page of lease by relay ID.
+ GET_LEASE4_RELAYID_QST, // Get page of leases by relay ID and query start time.
+ GET_LEASE4_RELAYID_QSET, // Get page of leases by relay ID and query start and end times.
+ GET_LEASE4_RELAYID_QET, // Get page of leases by relay ID and query end time.
+ GET_LEASE4_REMOTEID, // Get page of lease by remote ID.
+ GET_LEASE4_REMOTEID_QST, // Get page of leases by remote ID and query start time.
+ GET_LEASE4_REMOTEID_QSET, // Get page of leases by remote ID and query start and end times.
+ GET_LEASE4_REMOTEID_QET, // Get page of leases by remote ID and query end time.
GET_LEASE6, // Get all IPv6 leases
GET_LEASE6_ADDR, // Get lease6 by address
GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID
libdhcpsrv_unittests_SOURCES += ncr_generator_unittest.cc
if HAVE_MYSQL
libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += mysql_lease_extended_info_unittest.cc
libdhcpsrv_unittests_SOURCES += mysql_host_data_source_unittest.cc
endif
if HAVE_PGSQL
libdhcpsrv_unittests_SOURCES += pgsql_lease_mgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += pgsql_lease_extended_info_unittest.cc
libdhcpsrv_unittests_SOURCES += pgsql_host_data_source_unittest.cc
endif
libdhcpsrv_unittests_SOURCES += pool_unittest.cc
--- /dev/null
+// Copyright (C) 2023 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <cc/data.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/mysql_lease_mgr.h>
+#include <mysql/testutils/mysql_schema.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/multi_threading_utils.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::db;
+using namespace isc::db::test;
+using namespace isc::dhcp;
+using namespace isc::test;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief IPv4 addresses used in the tests.
+const vector<string> ADDRESS4 = {
+ "192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3",
+ "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7"
+};
+
+/// @brief DUIDs used in the tests.
+const vector<string> DUIDS = {
+ "wwwwwwww", "BBBBBBBB", "::::::::", "0123456789acdef",
+ "BBBBBBBB", "$$$$$$$$", "^^^^^^^^", "\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
+};
+
+/// @brief Test fixture class for extended info tests.
+class MySqlExtendedInfoTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ MySqlExtendedInfoTest() {
+ // Ensure we have the proper schema with no transient data.
+ createMySQLSchema();
+
+ // Connect to the database.
+ try {
+ LeaseMgrFactory::create(validMySQLConnectionString());
+ } catch (...) {
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the MySQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
+ throw;
+ }
+
+ lease_mgr_ = &(LeaseMgrFactory::instance());
+ leases4.clear();
+ MultiThreadingMgr::instance().setMode(false);
+ now_ = time(0);
+ }
+
+ /// @brief Destructor.
+ ~MySqlExtendedInfoTest() {
+ LeaseMgrFactory::destroy();
+ // If data wipe enabled, delete transient data otherwise destroy
+ // the schema.
+ destroyMySQLSchema();
+
+ leases4.clear();
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Create and set v4 leases.
+ ///
+ /// @param insert When true insert in the database.
+ void initLease4(bool insert = true) {
+ ASSERT_EQ(ADDRESS4.size(), DUIDS.size());
+ for (size_t i = 0; i < ADDRESS4.size(); ++i) {
+ Lease4Ptr lease;
+ vector<uint8_t> hwaddr_data(5, 0x08);
+ hwaddr_data.push_back(0x80 + i);
+ HWAddrPtr hwaddr(new HWAddr(hwaddr_data, HTYPE_ETHER));
+ vector<uint8_t> client_id = createFromString(DUIDS[i]);
+ IOAddress address(ADDRESS4[i]);
+ ASSERT_NO_THROW(lease.reset(new Lease4(address, hwaddr,
+ &client_id[0],
+ client_id.size(),
+ 1000, now_,
+ static_cast<SubnetID>(i))));
+ leases4.push_back(lease);
+ if (insert) {
+ EXPECT_TRUE(lease_mgr_->addLease(lease));
+ }
+ }
+ ASSERT_EQ(ADDRESS4.size(), leases4.size());
+ }
+
+ /// @brief Create a vector of uint8_t from a string.
+ ///
+ /// @param content A not empty string holding the content.
+ /// @return A vector of uint8_t with the given content.
+ inline vector<uint8_t> createFromString(const string& content) {
+ vector<uint8_t> v;
+ v.resize(content.size());
+ memmove(&v[0], &content[0], v.size());
+ return (v);
+ }
+
+ /// @brief Test initLease4.
+ void testInitLease4();
+
+ /// @brief Test getLease4ByRelayId.
+ void testGetLeases4ByRelayId();
+
+ /// @brief Test getLease4ByRemoteId.
+ void testGetLeases4ByRemoteId();
+
+ /// @brief Lease manager.
+ LeaseMgr* lease_mgr_;
+
+ /// @brief V4 leases.
+ Lease4Collection leases4;
+
+ /// @brief Current timestamp.
+ time_t now_;
+};
+
+/// @brief Verifies that the lease manager can add the v4 leases.
+void
+MySqlExtendedInfoTest::testInitLease4() {
+ initLease4();
+ EXPECT_EQ(8, leases4.size());
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ Lease4Collection got;
+ // Use the page version as it returns leases in order.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4(zero, LeasePageSize(100)));
+ ASSERT_EQ(leases4.size(), got.size());
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ ConstElementPtr expected = leases4[i]->toElement();
+ LeasePtr lease = got[i];
+ ASSERT_TRUE(lease);
+ EXPECT_TRUE(expected->equals(*lease->toElement()))
+ << "expected: " << expected->str() << "\n"
+ << "got: " << lease->toElement()->str() << "\n";
+ }
+}
+
+TEST_F(MySqlExtendedInfoTest, initLease4) {
+ testInitLease4();
+}
+
+TEST_F(MySqlExtendedInfoTest, initLease4MultiThreading) {
+ MultiThreadingTest mt(true);
+ testInitLease4();
+}
+
+/// @brief Verifies that getLeases4ByRelayId works as expected.
+void
+MySqlExtendedInfoTest::testGetLeases4ByRelayId() {
+ // Lease manager is created with empty tables.
+ initLease4(false);
+
+ // Create leases.
+ IOAddress addr0(ADDRESS4[0]);
+ IOAddress addr1(ADDRESS4[1]);
+ IOAddress addr2(ADDRESS4[2]);
+ IOAddress addr3(ADDRESS4[3]);
+ IOAddress addr4(ADDRESS4[4]);
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ vector<uint8_t> relay_id0 = { 0xaa, 0xbb, 0xcc };
+ vector<uint8_t> relay_id1 = { 1, 2, 3, 4 };
+ vector<uint8_t> relay_id2 = createFromString(DUIDS[2]);
+ string user_context_txt0 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt0 += " \"sub-options\": \"0C03AABBCC\",";
+ user_context_txt0 += " \"relay-id\": \"AABBCC\" } } }";
+ ElementPtr user_context0;
+ ASSERT_NO_THROW(user_context0 = Element::fromJSON(user_context_txt0));
+ string user_context_txt1 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt1 += " \"sub-options\": \"0C0401020304\",";
+ user_context_txt1 += " \"relay-id\": \"01020304\" } } }";
+ ElementPtr user_context1;
+ ASSERT_NO_THROW(user_context1 = Element::fromJSON(user_context_txt1));
+
+ Lease4Ptr lease;
+ // lease0: addr0, id0, now.
+ lease = leases4[0];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+
+ // lease1: addr1, id1, now.
+ lease = leases4[1];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id1;
+ lease->setContext(user_context1);
+
+ // lease2: addr2, id0, now - 500.
+ lease = leases4[2];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 500;
+
+ // lease3: addr3, id0, now - 800.
+ lease = leases4[3];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 800;
+
+ // lease4: addr4, id0, now - 100.
+ lease = leases4[4];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 100;
+
+ // Add leases.
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ EXPECT_TRUE(lease_mgr_->addLease(leases4[i]));
+ }
+
+ Lease4Collection got;
+ // Unknown relay id #2: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id2,
+ zero,
+ LeasePageSize(100)));
+ EXPECT_EQ(0, got.size());
+
+ // Unknown relay id #2, now - 1000, now + 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id2,
+ zero,
+ LeasePageSize(100),
+ now_ - 1000,
+ now_ + 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, now - 2000, now - 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 2000,
+ now_ - 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, now + 1000, now + 2000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ + 1000,
+ now_ + 2000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0: 3 entries (0, 2, 3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100)));
+ ASSERT_EQ(4, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[3];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, partial: 2 entries (0, 2).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, partial from previous: 2 entries (3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr2,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, final partial: no entries.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr4,
+ LeasePageSize(2)));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, from now - 500: 3 entries (0, 2, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 500));
+ ASSERT_EQ(3, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, to now - 200: 3 entries (2, 3).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ 0, now_ - 200));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, partial: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, partial from 2: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr2,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, final partial.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr4,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ EXPECT_EQ(0, got.size());
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases4ByRelayId) {
+ testGetLeases4ByRelayId();
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases4ByRelayIdMultiThreading) {
+ MultiThreadingTest mt(true);
+ testGetLeases4ByRelayId();
+}
+
+/// @brief Verifies that getLeases4ByRemoteId works as expected.
+void
+MySqlExtendedInfoTest::testGetLeases4ByRemoteId() {
+ // Lease manager is created with empty tables.
+ initLease4(true);
+
+ // Update leases.
+ IOAddress addr0(ADDRESS4[0]);
+ IOAddress addr1(ADDRESS4[1]);
+ IOAddress addr2(ADDRESS4[2]);
+ IOAddress addr3(ADDRESS4[3]);
+ IOAddress addr4(ADDRESS4[4]);
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ vector<uint8_t> remote_id0 = { 1, 2, 3, 4 };
+ vector<uint8_t> remote_id1 = { 0xaa, 0xbb, 0xcc };
+ vector<uint8_t> remote_id2 = createFromString(DUIDS[2]);
+ string user_context_txt0 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt0 += " \"sub-options\": \"020401020304\",";
+ user_context_txt0 += " \"remote-id\": \"01020304\" } } }";
+ ElementPtr user_context0;
+ ASSERT_NO_THROW(user_context0 = Element::fromJSON(user_context_txt0));
+ string user_context_txt1 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt1 += " \"sub-options\": \"0203AABBCC\",";
+ user_context_txt1 += " \"remote-id\": \"AABBCC\" } } }";
+ ElementPtr user_context1;
+ ASSERT_NO_THROW(user_context1 = Element::fromJSON(user_context_txt1));
+
+ Lease4Ptr lease;
+ // lease0: addr0, id0, now.
+ lease = leases4[0];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+
+ // lease1: addr1, id1, now.
+ lease = leases4[1];
+ lease->remote_id_ = remote_id1;
+ lease->setContext(user_context1);
+
+ // lease2: addr2, id0, now - 500.
+ lease = leases4[2];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 500;
+
+ // lease3: addr3, id0, now - 800.
+ lease = leases4[3];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 800;
+
+ // lease4: addr4, id0, now - 100.
+ lease = leases4[4];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 100;
+
+ // Update leases.
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ EXPECT_NO_THROW(lease_mgr_->updateLease4(leases4[i]));
+ }
+
+ Lease4Collection got;
+ // Unknown remote id #2: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id2,
+ zero,
+ LeasePageSize(100)));
+ EXPECT_EQ(0, got.size());
+
+ // Unknown remote id #2, now - 1000, now + 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id2,
+ zero,
+ LeasePageSize(100),
+ now_ - 1000,
+ now_ + 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, now - 2000, now - 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 2000,
+ now_ - 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, now + 1000, now + 2000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ + 1000,
+ now_ + 2000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0: 3 entries (0, 2, 3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100)));
+ ASSERT_EQ(4, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[3];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, partial: 2 entries (0, 2).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, partial from previous: 2 entries (3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr2,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, final partial: no entries.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr4,
+ LeasePageSize(2)));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, from now - 500: 3 entries (0, 2, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 500));
+ ASSERT_EQ(3, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, to now - 200: 3 entries (2, 3).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ 0, now_ - 200));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, partial: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, partial from 2: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr2,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, final partial.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr4,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ EXPECT_EQ(0, got.size());
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases4ByRemoteId) {
+ testGetLeases4ByRemoteId();
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases4ByRemoteIdMultiThreading) {
+ MultiThreadingTest mt(true);
+ testGetLeases4ByRemoteId();
+}
+
+} // namespace
--- /dev/null
+// Copyright (C) 2023 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <cc/data.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/pgsql_lease_mgr.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/multi_threading_utils.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::db;
+using namespace isc::db::test;
+using namespace isc::dhcp;
+using namespace isc::test;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief IPv4 addresses used in the tests.
+const vector<string> ADDRESS4 = {
+ "192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3",
+ "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7"
+};
+
+/// @brief DUIDs used in the tests.
+const vector<string> DUIDS = {
+ "wwwwwwww", "BBBBBBBB", "::::::::", "0123456789acdef",
+ "BBBBBBBB", "$$$$$$$$", "^^^^^^^^", "\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
+};
+
+/// @brief Test fixture class for extended info tests.
+class PgSqlExtendedInfoTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ PgSqlExtendedInfoTest() {
+ // Ensure we have the proper schema with no transient data.
+ createPgSQLSchema();
+
+ // Connect to the database.
+ try {
+ LeaseMgrFactory::create(validPgSQLConnectionString());
+ } catch (...) {
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the PostgreSQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
+ throw;
+ }
+
+ lease_mgr_ = &(LeaseMgrFactory::instance());
+ leases4.clear();
+ MultiThreadingMgr::instance().setMode(false);
+ now_ = time(0);
+ }
+
+ /// @brief Destructor.
+ ~PgSqlExtendedInfoTest() {
+ LeaseMgrFactory::destroy();
+ // If data wipe enabled, delete transient data otherwise destroy
+ // the schema.
+ destroyPgSQLSchema();
+
+ leases4.clear();
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Create and set v4 leases.
+ ///
+ /// @param insert When true insert in the database.
+ void initLease4(bool insert = true) {
+ ASSERT_EQ(ADDRESS4.size(), DUIDS.size());
+ for (size_t i = 0; i < ADDRESS4.size(); ++i) {
+ Lease4Ptr lease;
+ vector<uint8_t> hwaddr_data(5, 0x08);
+ hwaddr_data.push_back(0x80 + i);
+ HWAddrPtr hwaddr(new HWAddr(hwaddr_data, HTYPE_ETHER));
+ vector<uint8_t> client_id = createFromString(DUIDS[i]);
+ IOAddress address(ADDRESS4[i]);
+ ASSERT_NO_THROW(lease.reset(new Lease4(address, hwaddr,
+ &client_id[0],
+ client_id.size(),
+ 1000, now_,
+ static_cast<SubnetID>(i))));
+ leases4.push_back(lease);
+ if (insert) {
+ EXPECT_TRUE(lease_mgr_->addLease(lease));
+ }
+ }
+ ASSERT_EQ(ADDRESS4.size(), leases4.size());
+ }
+
+ /// @brief Create a vector of uint8_t from a string.
+ ///
+ /// @param content A not empty string holding the content.
+ /// @return A vector of uint8_t with the given content.
+ inline vector<uint8_t> createFromString(const string& content) {
+ vector<uint8_t> v;
+ v.resize(content.size());
+ memmove(&v[0], &content[0], v.size());
+ return (v);
+ }
+
+ /// @brief Test initLease4.
+ void testInitLease4();
+
+ /// @brief Test getLease4ByRelayId.
+ void testGetLeases4ByRelayId();
+
+ /// @brief Test getLease4ByRemoteId.
+ void testGetLeases4ByRemoteId();
+
+ /// @brief Lease manager.
+ LeaseMgr* lease_mgr_;
+
+ /// @brief V4 leases.
+ Lease4Collection leases4;
+
+ /// @brief Current timestamp.
+ time_t now_;
+};
+
+/// @brief Verifies that the lease manager can add the v4 leases.
+void
+PgSqlExtendedInfoTest::testInitLease4() {
+ initLease4();
+ EXPECT_EQ(8, leases4.size());
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ Lease4Collection got;
+ // Use the page version as it returns leases in order.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4(zero, LeasePageSize(100)));
+ ASSERT_EQ(leases4.size(), got.size());
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ ConstElementPtr expected = leases4[i]->toElement();
+ LeasePtr lease = got[i];
+ ASSERT_TRUE(lease);
+ EXPECT_TRUE(expected->equals(*lease->toElement()))
+ << "expected: " << expected->str() << "\n"
+ << "got: " << lease->toElement()->str() << "\n";
+ }
+}
+
+TEST_F(PgSqlExtendedInfoTest, initLease4) {
+ testInitLease4();
+}
+
+TEST_F(PgSqlExtendedInfoTest, initLease4MultiThreading) {
+ MultiThreadingTest mt(true);
+ testInitLease4();
+}
+
+/// @brief Verifies that getLeases4ByRelayId works as expected.
+void
+PgSqlExtendedInfoTest::testGetLeases4ByRelayId() {
+ // Lease manager is created with empty tables.
+ initLease4(false);
+
+ // Create leases.
+ IOAddress addr0(ADDRESS4[0]);
+ IOAddress addr1(ADDRESS4[1]);
+ IOAddress addr2(ADDRESS4[2]);
+ IOAddress addr3(ADDRESS4[3]);
+ IOAddress addr4(ADDRESS4[4]);
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ vector<uint8_t> relay_id0 = { 0xaa, 0xbb, 0xcc };
+ vector<uint8_t> relay_id1 = { 1, 2, 3, 4 };
+ vector<uint8_t> relay_id2 = createFromString(DUIDS[2]);
+ string user_context_txt0 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt0 += " \"sub-options\": \"0C03AABBCC\",";
+ user_context_txt0 += " \"relay-id\": \"AABBCC\" } } }";
+ ElementPtr user_context0;
+ ASSERT_NO_THROW(user_context0 = Element::fromJSON(user_context_txt0));
+ string user_context_txt1 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt1 += " \"sub-options\": \"0C0401020304\",";
+ user_context_txt1 += " \"relay-id\": \"01020304\" } } }";
+ ElementPtr user_context1;
+ ASSERT_NO_THROW(user_context1 = Element::fromJSON(user_context_txt1));
+
+ Lease4Ptr lease;
+ // lease0: addr0, id0, now.
+ lease = leases4[0];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+
+ // lease1: addr1, id1, now.
+ lease = leases4[1];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id1;
+ lease->setContext(user_context1);
+
+ // lease2: addr2, id0, now - 500.
+ lease = leases4[2];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 500;
+
+ // lease3: addr3, id0, now - 800.
+ lease = leases4[3];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 800;
+
+ // lease4: addr4, id0, now - 100.
+ lease = leases4[4];
+ ASSERT_TRUE(lease);
+ lease->relay_id_ = relay_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 100;
+
+ // Add leases.
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ EXPECT_TRUE(lease_mgr_->addLease(leases4[i]));
+ }
+
+ Lease4Collection got;
+ // Unknown relay id #2: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id2,
+ zero,
+ LeasePageSize(100)));
+ EXPECT_EQ(0, got.size());
+
+ // Unknown relay id #2, now - 1000, now + 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id2,
+ zero,
+ LeasePageSize(100),
+ now_ - 1000,
+ now_ + 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, now - 2000, now - 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 2000,
+ now_ - 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, now + 1000, now + 2000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ + 1000,
+ now_ + 2000));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0: 3 entries (0, 2, 3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100)));
+ ASSERT_EQ(4, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[3];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, partial: 2 entries (0, 2).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, partial from previous: 2 entries (3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr2,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, final partial: no entries.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr4,
+ LeasePageSize(2)));
+ EXPECT_EQ(0, got.size());
+
+ // Relay id #0, from now - 500: 3 entries (0, 2, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 500));
+ ASSERT_EQ(3, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, to now - 200: 3 entries (2, 3).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(100),
+ 0, now_ - 200));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, partial: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ zero,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, partial from 2: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr2,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(relay_id0, lease->relay_id_);
+
+ // Relay id #0, from now - 500 to now - 100, final partial.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRelayId(relay_id0,
+ addr4,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ EXPECT_EQ(0, got.size());
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases4ByRelayId) {
+ testGetLeases4ByRelayId();
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases4ByRelayIdMultiThreading) {
+ MultiThreadingTest mt(true);
+ testGetLeases4ByRelayId();
+}
+
+/// @brief Verifies that getLeases4ByRemoteId works as expected.
+void
+PgSqlExtendedInfoTest::testGetLeases4ByRemoteId() {
+ // Lease manager is created with empty tables.
+ initLease4(true);
+
+ // Update leases.
+ IOAddress addr0(ADDRESS4[0]);
+ IOAddress addr1(ADDRESS4[1]);
+ IOAddress addr2(ADDRESS4[2]);
+ IOAddress addr3(ADDRESS4[3]);
+ IOAddress addr4(ADDRESS4[4]);
+ IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+ vector<uint8_t> remote_id0 = { 1, 2, 3, 4 };
+ vector<uint8_t> remote_id1 = { 0xaa, 0xbb, 0xcc };
+ vector<uint8_t> remote_id2 = createFromString(DUIDS[2]);
+ string user_context_txt0 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt0 += " \"sub-options\": \"020401020304\",";
+ user_context_txt0 += " \"remote-id\": \"01020304\" } } }";
+ ElementPtr user_context0;
+ ASSERT_NO_THROW(user_context0 = Element::fromJSON(user_context_txt0));
+ string user_context_txt1 = "{ \"ISC\": { \"relay-agent-info\": {";
+ user_context_txt1 += " \"sub-options\": \"0203AABBCC\",";
+ user_context_txt1 += " \"remote-id\": \"AABBCC\" } } }";
+ ElementPtr user_context1;
+ ASSERT_NO_THROW(user_context1 = Element::fromJSON(user_context_txt1));
+
+ Lease4Ptr lease;
+ // lease0: addr0, id0, now.
+ lease = leases4[0];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+
+ // lease1: addr1, id1, now.
+ lease = leases4[1];
+ lease->remote_id_ = remote_id1;
+ lease->setContext(user_context1);
+
+ // lease2: addr2, id0, now - 500.
+ lease = leases4[2];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 500;
+
+ // lease3: addr3, id0, now - 800.
+ lease = leases4[3];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 800;
+
+ // lease4: addr4, id0, now - 100.
+ lease = leases4[4];
+ lease->remote_id_ = remote_id0;
+ lease->setContext(user_context0);
+ lease->cltt_ = now_ - 100;
+
+ // Update leases.
+ for (size_t i = 0; i < leases4.size(); ++i) {
+ EXPECT_NO_THROW(lease_mgr_->updateLease4(leases4[i]));
+ }
+
+ Lease4Collection got;
+ // Unknown remote id #2: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id2,
+ zero,
+ LeasePageSize(100)));
+ EXPECT_EQ(0, got.size());
+
+ // Unknown remote id #2, now - 1000, now + 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id2,
+ zero,
+ LeasePageSize(100),
+ now_ - 1000,
+ now_ + 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, now - 2000, now - 1000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 2000,
+ now_ - 1000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, now + 1000, now + 2000: nothing.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ + 1000,
+ now_ + 2000));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0: 3 entries (0, 2, 3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100)));
+ ASSERT_EQ(4, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[3];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, partial: 2 entries (0, 2).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, partial from previous: 2 entries (3, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr2,
+ LeasePageSize(2)));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, final partial: no entries.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr4,
+ LeasePageSize(2)));
+ EXPECT_EQ(0, got.size());
+
+ // Remote id #0, from now - 500: 3 entries (0, 2, 4).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ now_ - 500));
+ ASSERT_EQ(3, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[0]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[2];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, to now - 200: 3 entries (2, 3).
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(100),
+ 0, now_ - 200));
+ ASSERT_EQ(2, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+ lease = got[1];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[3]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, partial: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ zero,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[2]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, partial from 2: 1 entry.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr2,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ ASSERT_EQ(1, got.size());
+ lease = got[0];
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(*lease, *leases4[4]);
+ EXPECT_EQ(remote_id0, lease->remote_id_);
+
+ // Remote id #0, from now - 500 to now - 100, final partial.
+ EXPECT_NO_THROW(got = lease_mgr_->getLeases4ByRemoteId(remote_id0,
+ addr4,
+ LeasePageSize(1),
+ now_ - 500,
+ now_ - 100));
+ EXPECT_EQ(0, got.size());
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases4ByRemoteId) {
+ testGetLeases4ByRemoteId();
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases4ByRemoteIdMultiThreading) {
+ MultiThreadingTest mt(true);
+ testGetLeases4ByRemoteId();
+}
+
+} // namespace