mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[#2408] Improved handling rejected leases
The new communication state functions are now MT safe. The rejected leases have also expiration time attached.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <boost/pointer_cast.hpp>
|
#include <boost/pointer_cast.hpp>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -324,6 +325,47 @@ CommunicationState::getAnalyzedMessagesCount() const {
|
|||||||
return (analyzed_messages_count_);
|
return (analyzed_messages_count_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CommunicationState::getRejectedLeaseUpdatesCount() {
|
||||||
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
|
return (getRejectedLeaseUpdatesCountInternal());
|
||||||
|
} else {
|
||||||
|
return (getRejectedLeaseUpdatesCountInternal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CommunicationState::reportRejectedLeaseUpdate(const PktPtr& message,
|
||||||
|
const uint32_t lifetime) {
|
||||||
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
|
return (reportRejectedLeaseUpdateInternal(message, lifetime));
|
||||||
|
} else {
|
||||||
|
return (reportRejectedLeaseUpdateInternal(message, lifetime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CommunicationState::reportSuccessfulLeaseUpdate(const PktPtr& message) {
|
||||||
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
|
return (reportSuccessfulLeaseUpdateInternal(message));
|
||||||
|
} else {
|
||||||
|
return (reportSuccessfulLeaseUpdateInternal(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CommunicationState::clearRejectedLeaseUpdates() {
|
||||||
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
|
return (clearRejectedLeaseUpdatesInternal());
|
||||||
|
} else {
|
||||||
|
return (clearRejectedLeaseUpdatesInternal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState::clockSkewShouldWarn() {
|
CommunicationState::clockSkewShouldWarn() {
|
||||||
if (MultiThreadingMgr::instance().getMode()) {
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
@@ -364,7 +406,7 @@ CommunicationState::clockSkewShouldWarnInternal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState::clockSkewShouldTerminate() const {
|
CommunicationState::clockSkewShouldTerminate() {
|
||||||
if (MultiThreadingMgr::instance().getMode()) {
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
std::lock_guard<std::mutex> lk(*mutex_);
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
// Issue a warning if the clock skew is greater than 60s.
|
// Issue a warning if the clock skew is greater than 60s.
|
||||||
@@ -375,7 +417,7 @@ CommunicationState::clockSkewShouldTerminate() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState::clockSkewShouldTerminateInternal() const {
|
CommunicationState::clockSkewShouldTerminateInternal() {
|
||||||
if (isClockSkewGreater(TERM_CLOCK_SKEW)) {
|
if (isClockSkewGreater(TERM_CLOCK_SKEW)) {
|
||||||
LOG_ERROR(ha_logger, HA_HIGH_CLOCK_SKEW_CAUSES_TERMINATION)
|
LOG_ERROR(ha_logger, HA_HIGH_CLOCK_SKEW_CAUSES_TERMINATION)
|
||||||
.arg(logFormatClockSkewInternal());
|
.arg(logFormatClockSkewInternal());
|
||||||
@@ -385,7 +427,7 @@ CommunicationState::clockSkewShouldTerminateInternal() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState::rejectedLeaseUpdatesShouldTerminate() const {
|
CommunicationState::rejectedLeaseUpdatesShouldTerminate() {
|
||||||
if (MultiThreadingMgr::instance().getMode()) {
|
if (MultiThreadingMgr::instance().getMode()) {
|
||||||
std::lock_guard<std::mutex> lk(*mutex_);
|
std::lock_guard<std::mutex> lk(*mutex_);
|
||||||
return (rejectedLeaseUpdatesShouldTerminateInternal());
|
return (rejectedLeaseUpdatesShouldTerminateInternal());
|
||||||
@@ -395,9 +437,9 @@ CommunicationState::rejectedLeaseUpdatesShouldTerminate() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState::rejectedLeaseUpdatesShouldTerminateInternal() const {
|
CommunicationState::rejectedLeaseUpdatesShouldTerminateInternal() {
|
||||||
if (config_->getMaxRejectedLeaseUpdates() &&
|
if (config_->getMaxRejectedLeaseUpdates() &&
|
||||||
(config_->getMaxRejectedLeaseUpdates() <= getRejectedLeaseUpdatesCount())) {
|
(config_->getMaxRejectedLeaseUpdates() <= getRejectedLeaseUpdatesCountInternal())) {
|
||||||
LOG_ERROR(ha_logger, HA_REJECTED_LEASE_UPDATES_CAUSE_TERMINATION);
|
LOG_ERROR(ha_logger, HA_REJECTED_LEASE_UPDATES_CAUSE_TERMINATION);
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
@@ -701,28 +743,33 @@ CommunicationState4::clearConnectingClients() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CommunicationState4::getRejectedLeaseUpdatesCount() const {
|
CommunicationState4::getRejectedLeaseUpdatesCountInternal() {
|
||||||
return (rejected_clients_.size());
|
return (getRejectedLeaseUpdatesCountFromContainer(rejected_clients_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState4::reportRejectedLeaseUpdate(const PktPtr& message) {
|
CommunicationState4::reportRejectedLeaseUpdateInternal(const PktPtr& message, const uint32_t lifetime) {
|
||||||
Pkt4Ptr msg = boost::dynamic_pointer_cast<Pkt4>(message);
|
Pkt4Ptr msg = boost::dynamic_pointer_cast<Pkt4>(message);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
isc_throw(BadValue, "DHCP message for which the lease update was rejected is not a DHCPv4 message");
|
isc_throw(BadValue, "DHCP message for which the lease update was rejected is not a DHCPv4 message");
|
||||||
}
|
}
|
||||||
auto client_id = getClientId(message, DHO_DHCP_CLIENT_IDENTIFIER);
|
auto client_id = getClientId(message, DHO_DHCP_CLIENT_IDENTIFIER);
|
||||||
|
RejectedClient4 client{ msg->getHWAddr()->hwaddr_, client_id, time(NULL) + lifetime };
|
||||||
auto existing_client = rejected_clients_.find(boost::make_tuple(msg->getHWAddr()->hwaddr_, client_id));
|
auto existing_client = rejected_clients_.find(boost::make_tuple(msg->getHWAddr()->hwaddr_, client_id));
|
||||||
if (existing_client == rejected_clients_.end()) {
|
if (existing_client == rejected_clients_.end()) {
|
||||||
RejectedClient4 new_client{ msg->getHWAddr()->hwaddr_, client_id };
|
rejected_clients_.insert(client);
|
||||||
rejected_clients_.insert(new_client);
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
rejected_clients_.replace(existing_client, client);
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState4::reportSuccessfulLeaseUpdate(const PktPtr& message) {
|
CommunicationState4::reportSuccessfulLeaseUpdateInternal(const PktPtr& message) {
|
||||||
|
// Early check if there is anything to do.
|
||||||
|
if (getRejectedLeaseUpdatesCountInternal() == 0) {
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
Pkt4Ptr msg = boost::dynamic_pointer_cast<Pkt4>(message);
|
Pkt4Ptr msg = boost::dynamic_pointer_cast<Pkt4>(message);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
isc_throw(BadValue, "DHCP message for which the lease update was successful is not a DHCPv4 message");
|
isc_throw(BadValue, "DHCP message for which the lease update was successful is not a DHCPv4 message");
|
||||||
@@ -737,7 +784,7 @@ CommunicationState4::reportSuccessfulLeaseUpdate(const PktPtr& message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CommunicationState4::clearRejectedLeaseUpdates() {
|
CommunicationState4::clearRejectedLeaseUpdatesInternal() {
|
||||||
rejected_clients_.clear();
|
rejected_clients_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,12 +916,12 @@ CommunicationState6::clearConnectingClients() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CommunicationState6::getRejectedLeaseUpdatesCount() const {
|
CommunicationState6::getRejectedLeaseUpdatesCountInternal() {
|
||||||
return (rejected_clients_.size());
|
return (getRejectedLeaseUpdatesCountFromContainer(rejected_clients_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState6::reportRejectedLeaseUpdate(const PktPtr& message) {
|
CommunicationState6::reportRejectedLeaseUpdateInternal(const PktPtr& message, const uint32_t lifetime) {
|
||||||
Pkt6Ptr msg = boost::dynamic_pointer_cast<Pkt6>(message);
|
Pkt6Ptr msg = boost::dynamic_pointer_cast<Pkt6>(message);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
isc_throw(BadValue, "DHCP message for which the lease update was rejected is not a DHCPv6 message");
|
isc_throw(BadValue, "DHCP message for which the lease update was rejected is not a DHCPv6 message");
|
||||||
@@ -883,17 +930,22 @@ CommunicationState6::reportRejectedLeaseUpdate(const PktPtr& message) {
|
|||||||
if (duid.empty()) {
|
if (duid.empty()) {
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
RejectedClient6 client{ duid, time(NULL) + lifetime };
|
||||||
auto existing_client = rejected_clients_.find(duid);
|
auto existing_client = rejected_clients_.find(duid);
|
||||||
if (existing_client == rejected_clients_.end()) {
|
if (existing_client == rejected_clients_.end()) {
|
||||||
RejectedClient6 new_client{ duid };
|
rejected_clients_.insert(client);
|
||||||
rejected_clients_.insert(new_client);
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
rejected_clients_.replace(existing_client, client);
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CommunicationState6::reportSuccessfulLeaseUpdate(const PktPtr& message) {
|
CommunicationState6::reportSuccessfulLeaseUpdateInternal(const PktPtr& message) {
|
||||||
|
// Early check if there is anything to do.
|
||||||
|
if (getRejectedLeaseUpdatesCountInternal() == 0) {
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
Pkt6Ptr msg = boost::dynamic_pointer_cast<Pkt6>(message);
|
Pkt6Ptr msg = boost::dynamic_pointer_cast<Pkt6>(message);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
isc_throw(BadValue, "DHCP message for which the lease update was successful is not a DHCPv6 message");
|
isc_throw(BadValue, "DHCP message for which the lease update was successful is not a DHCPv6 message");
|
||||||
@@ -911,10 +963,9 @@ CommunicationState6::reportSuccessfulLeaseUpdate(const PktPtr& message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CommunicationState6::clearRejectedLeaseUpdates() {
|
CommunicationState6::clearRejectedLeaseUpdatesInternal() {
|
||||||
rejected_clients_.clear();
|
rejected_clients_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace isc::ha
|
} // end of namespace isc::ha
|
||||||
} // end of namespace isc
|
} // end of namespace isc
|
||||||
|
@@ -299,13 +299,65 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// @brief Returns the number of lease updates rejected by the partner (MT safe).
|
||||||
|
///
|
||||||
|
/// Each rejected lease update is counted only once if it failed
|
||||||
|
/// multiple times. Before returning the counter, it discards expired
|
||||||
|
/// rejected lease updates.
|
||||||
|
///
|
||||||
|
/// @return Current rejected lease update number count.
|
||||||
|
size_t getRejectedLeaseUpdatesCount();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Returns the number of lease updates rejected by the partner.
|
/// @brief Returns the number of lease updates rejected by the partner.
|
||||||
///
|
///
|
||||||
/// Each rejected lease update is counted only once if it failed
|
/// Each rejected lease update is counted only once if it failed
|
||||||
/// multiple times
|
/// multiple times. Before returning the counter, it discards expired
|
||||||
|
/// rejected lease updates.
|
||||||
///
|
///
|
||||||
/// @return Current rejected lease update number count.
|
/// @return Current rejected lease update number count.
|
||||||
virtual size_t getRejectedLeaseUpdatesCount() const = 0;
|
virtual size_t getRejectedLeaseUpdatesCountInternal() = 0;
|
||||||
|
|
||||||
|
/// @brief Extracts the number of lease updates rejected by the partner
|
||||||
|
/// from the specified container.
|
||||||
|
///
|
||||||
|
/// @param rejected_clients container holding rejected clients (v4 or v6).
|
||||||
|
/// @tparam RejectedClientsType type of the container holding rejected
|
||||||
|
/// clients.
|
||||||
|
/// @return Current rejected lease update number count.
|
||||||
|
template<typename RejectedClientsType>
|
||||||
|
static size_t getRejectedLeaseUpdatesCountFromContainer(RejectedClientsType& rejected_clients) {
|
||||||
|
if (rejected_clients.empty()) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
auto& idx = rejected_clients.template get<1>();
|
||||||
|
auto upper_limit = idx.upper_bound(time(NULL));
|
||||||
|
if (upper_limit != idx.end()) {
|
||||||
|
auto lower_limit = idx.cbegin();
|
||||||
|
idx.erase(lower_limit, upper_limit);
|
||||||
|
}
|
||||||
|
return (rejected_clients.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Marks that the lease update failed due to a conflict for the
|
||||||
|
/// specified DHCP message (MT safe).
|
||||||
|
///
|
||||||
|
/// If the conflict has been already reported for the given client, the
|
||||||
|
/// rejected lease count remains unchanged.
|
||||||
|
///
|
||||||
|
/// @param message DHCP message for which a lease update failed due to
|
||||||
|
/// a conflict.
|
||||||
|
/// @param lifetime a time in seconds after which the rejected lease
|
||||||
|
/// update entry should be discarded.
|
||||||
|
/// @return true if the update was rejected for the first time, false
|
||||||
|
/// otherwise.
|
||||||
|
bool reportRejectedLeaseUpdate(const dhcp::PktPtr& message,
|
||||||
|
const uint32_t lifetime = 86400);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Marks that the lease update failed due to a conflict for the
|
/// @brief Marks that the lease update failed due to a conflict for the
|
||||||
/// specified DHCP message.
|
/// specified DHCP message.
|
||||||
@@ -315,9 +367,26 @@ public:
|
|||||||
///
|
///
|
||||||
/// @param message DHCP message for which a lease update failed due to
|
/// @param message DHCP message for which a lease update failed due to
|
||||||
/// a conflict.
|
/// a conflict.
|
||||||
|
/// @param lifetime a time in seconds after which the rejected lease
|
||||||
|
/// update entry should be discarded.
|
||||||
/// @return true if the update was rejected for the first time, false
|
/// @return true if the update was rejected for the first time, false
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
virtual bool reportRejectedLeaseUpdate(const dhcp::PktPtr& message) = 0;
|
virtual bool reportRejectedLeaseUpdateInternal(const dhcp::PktPtr& message,
|
||||||
|
const uint32_t lifetime) = 0;
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Marks the lease update successful (MT safe).
|
||||||
|
///
|
||||||
|
/// If the lease update was previously marked "in conflict", it is
|
||||||
|
/// now cleared, effectively lowering the number of conflicted leases.
|
||||||
|
///
|
||||||
|
/// @param message DHCP message for which the lease update was
|
||||||
|
/// successful.
|
||||||
|
/// @return true when the lease was marked "in conflict" and it is
|
||||||
|
/// now cleared.
|
||||||
|
bool reportSuccessfulLeaseUpdate(const dhcp::PktPtr& message);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Marks the lease update successful.
|
/// @brief Marks the lease update successful.
|
||||||
///
|
///
|
||||||
@@ -328,10 +397,19 @@ public:
|
|||||||
/// successful.
|
/// successful.
|
||||||
/// @return true when the lease was marked "in conflict" and it is
|
/// @return true when the lease was marked "in conflict" and it is
|
||||||
/// now cleared.
|
/// now cleared.
|
||||||
virtual bool reportSuccessfulLeaseUpdate(const dhcp::PktPtr& message) = 0;
|
virtual bool reportSuccessfulLeaseUpdateInternal(const dhcp::PktPtr& message) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Clears rejected client leases (MT safe).
|
||||||
|
void clearRejectedLeaseUpdates();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Clears rejected client leases.
|
/// @brief Clears rejected client leases.
|
||||||
virtual void clearRejectedLeaseUpdates() = 0;
|
virtual void clearRejectedLeaseUpdatesInternal() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/// @brief Issues a warning about high clock skew between the active
|
/// @brief Issues a warning about high clock skew between the active
|
||||||
/// servers if one is warranted.
|
/// servers if one is warranted.
|
||||||
@@ -399,7 +477,7 @@ public:
|
|||||||
/// 60 seconds. In the future it may become configurable.
|
/// 60 seconds. In the future it may become configurable.
|
||||||
///
|
///
|
||||||
/// @return true if the HA service should enter "terminated" state.
|
/// @return true if the HA service should enter "terminated" state.
|
||||||
bool clockSkewShouldTerminate() const;
|
bool clockSkewShouldTerminate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @brief Indicates whether the HA service should enter "terminated"
|
/// @brief Indicates whether the HA service should enter "terminated"
|
||||||
@@ -418,7 +496,7 @@ private:
|
|||||||
/// 60 seconds. In the future it may become configurable.
|
/// 60 seconds. In the future it may become configurable.
|
||||||
///
|
///
|
||||||
/// @return true if the HA service should enter "terminated" state.
|
/// @return true if the HA service should enter "terminated" state.
|
||||||
bool clockSkewShouldTerminateInternal() const;
|
bool clockSkewShouldTerminateInternal();
|
||||||
|
|
||||||
/// @brief Checks if the clock skew is greater than the specified number
|
/// @brief Checks if the clock skew is greater than the specified number
|
||||||
/// of seconds.
|
/// of seconds.
|
||||||
@@ -437,7 +515,7 @@ public:
|
|||||||
/// exceeds the value of max-rejected-lease-updates, false when the
|
/// exceeds the value of max-rejected-lease-updates, false when the
|
||||||
/// max-rejected-lease-updates is 0 or is greater than the current
|
/// max-rejected-lease-updates is 0 or is greater than the current
|
||||||
/// number of rejected lease updates.
|
/// number of rejected lease updates.
|
||||||
bool rejectedLeaseUpdatesShouldTerminate() const;
|
bool rejectedLeaseUpdatesShouldTerminate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -448,7 +526,7 @@ private:
|
|||||||
/// exceeds the value of max-rejected-lease-updates, false when the
|
/// exceeds the value of max-rejected-lease-updates, false when the
|
||||||
/// max-rejected-lease-updates is 0 or is greater than the current
|
/// max-rejected-lease-updates is 0 or is greater than the current
|
||||||
/// number of rejected lease updates.
|
/// number of rejected lease updates.
|
||||||
bool rejectedLeaseUpdatesShouldTerminateInternal() const;
|
bool rejectedLeaseUpdatesShouldTerminateInternal();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -716,13 +794,16 @@ public:
|
|||||||
/// @return Number of unacked clients.
|
/// @return Number of unacked clients.
|
||||||
virtual size_t getUnackedClientsCount() const;
|
virtual size_t getUnackedClientsCount() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Returns the number of lease updates rejected by the partner.
|
/// @brief Returns the number of lease updates rejected by the partner.
|
||||||
///
|
///
|
||||||
/// Each rejected lease update is counted only once if it failed
|
/// Each rejected lease update is counted only once if it failed
|
||||||
/// multiple times
|
/// multiple times. Before returning the counter, it discards expired
|
||||||
|
/// rejected lease updates.
|
||||||
///
|
///
|
||||||
/// @return Current rejected lease update number count.
|
/// @return Current rejected lease update number count.
|
||||||
virtual size_t getRejectedLeaseUpdatesCount() const;
|
virtual size_t getRejectedLeaseUpdatesCountInternal();
|
||||||
|
|
||||||
/// @brief Marks that the lease update failed due to a conflict for the
|
/// @brief Marks that the lease update failed due to a conflict for the
|
||||||
/// specified DHCP message.
|
/// specified DHCP message.
|
||||||
@@ -732,9 +813,12 @@ public:
|
|||||||
///
|
///
|
||||||
/// @param message DHCP message for which a lease update failed due to
|
/// @param message DHCP message for which a lease update failed due to
|
||||||
/// a conflict.
|
/// a conflict.
|
||||||
|
/// @param lifetime a time in seconds after which the rejected lease
|
||||||
|
/// update entry should be discarded.
|
||||||
/// @return true if the update was rejected for the first time, false
|
/// @return true if the update was rejected for the first time, false
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
virtual bool reportRejectedLeaseUpdate(const dhcp::PktPtr& message);
|
virtual bool reportRejectedLeaseUpdateInternal(const dhcp::PktPtr& message,
|
||||||
|
const uint32_t lifetime);
|
||||||
|
|
||||||
/// @brief Marks the lease update successful.
|
/// @brief Marks the lease update successful.
|
||||||
///
|
///
|
||||||
@@ -745,12 +829,10 @@ public:
|
|||||||
/// successful.
|
/// successful.
|
||||||
/// @return true when the lease was marked "in conflict" and it is
|
/// @return true when the lease was marked "in conflict" and it is
|
||||||
/// now cleared.
|
/// now cleared.
|
||||||
virtual bool reportSuccessfulLeaseUpdate(const dhcp::PktPtr& message);
|
virtual bool reportSuccessfulLeaseUpdateInternal(const dhcp::PktPtr& message);
|
||||||
|
|
||||||
/// @brief Clears rejected client leases.
|
/// @brief Clears rejected client leases.
|
||||||
virtual void clearRejectedLeaseUpdates();
|
virtual void clearRejectedLeaseUpdatesInternal();
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// @brief Checks if the DHCPv4 message appears to be unanswered.
|
/// @brief Checks if the DHCPv4 message appears to be unanswered.
|
||||||
///
|
///
|
||||||
@@ -835,6 +917,7 @@ protected:
|
|||||||
struct RejectedClient4 {
|
struct RejectedClient4 {
|
||||||
std::vector<uint8_t> hwaddr_;
|
std::vector<uint8_t> hwaddr_;
|
||||||
std::vector<uint8_t> clientid_;
|
std::vector<uint8_t> clientid_;
|
||||||
|
int64_t expire_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Multi index container holding information about the clients
|
/// @brief Multi index container holding information about the clients
|
||||||
@@ -842,7 +925,11 @@ protected:
|
|||||||
typedef boost::multi_index_container<
|
typedef boost::multi_index_container<
|
||||||
RejectedClient4,
|
RejectedClient4,
|
||||||
boost::multi_index::indexed_by<
|
boost::multi_index::indexed_by<
|
||||||
ClientIdent4<RejectedClient4>
|
ClientIdent4<RejectedClient4>,
|
||||||
|
boost::multi_index::ordered_non_unique<
|
||||||
|
boost::multi_index::member<RejectedClient4, int64_t,
|
||||||
|
&RejectedClient4::expire_>
|
||||||
|
>
|
||||||
>
|
>
|
||||||
> RejectedClients4;
|
> RejectedClients4;
|
||||||
|
|
||||||
@@ -906,13 +993,16 @@ public:
|
|||||||
/// @return Number of unacked clients.
|
/// @return Number of unacked clients.
|
||||||
virtual size_t getUnackedClientsCount() const;
|
virtual size_t getUnackedClientsCount() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// @brief Returns the number of lease updates rejected by the partner.
|
/// @brief Returns the number of lease updates rejected by the partner.
|
||||||
///
|
///
|
||||||
/// Each rejected lease update is counted only once if it failed
|
/// Each rejected lease update is counted only once if it failed
|
||||||
/// multiple times
|
/// multiple times. Before returning the counter, it discards expired
|
||||||
|
/// rejected lease updates.
|
||||||
///
|
///
|
||||||
/// @return Current rejected lease update number count.
|
/// @return Current rejected lease update number count.
|
||||||
virtual size_t getRejectedLeaseUpdatesCount() const;
|
virtual size_t getRejectedLeaseUpdatesCountInternal();
|
||||||
|
|
||||||
/// @brief Marks that the lease update failed due to a conflict for the
|
/// @brief Marks that the lease update failed due to a conflict for the
|
||||||
/// specified DHCP message.
|
/// specified DHCP message.
|
||||||
@@ -922,9 +1012,12 @@ public:
|
|||||||
///
|
///
|
||||||
/// @param message DHCP message for which a lease update failed due to
|
/// @param message DHCP message for which a lease update failed due to
|
||||||
/// a conflict.
|
/// a conflict.
|
||||||
|
/// @param lifetime a time in seconds after which the rejected lease
|
||||||
|
/// update entry should be discarded.
|
||||||
/// @return true if the update was rejected for the first time, false
|
/// @return true if the update was rejected for the first time, false
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
virtual bool reportRejectedLeaseUpdate(const dhcp::PktPtr& message);
|
virtual bool reportRejectedLeaseUpdateInternal(const dhcp::PktPtr& message,
|
||||||
|
const uint32_t lifetime = 86400);
|
||||||
|
|
||||||
/// @brief Marks the lease update successful.
|
/// @brief Marks the lease update successful.
|
||||||
///
|
///
|
||||||
@@ -935,10 +1028,10 @@ public:
|
|||||||
/// successful.
|
/// successful.
|
||||||
/// @return true when the lease was marked "in conflict" and it is
|
/// @return true when the lease was marked "in conflict" and it is
|
||||||
/// now cleared.
|
/// now cleared.
|
||||||
virtual bool reportSuccessfulLeaseUpdate(const dhcp::PktPtr& message);
|
virtual bool reportSuccessfulLeaseUpdateInternal(const dhcp::PktPtr& message);
|
||||||
|
|
||||||
/// @brief Clears rejected client leases.
|
/// @brief Clears rejected client leases.
|
||||||
virtual void clearRejectedLeaseUpdates();
|
virtual void clearRejectedLeaseUpdatesInternal();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -1011,6 +1104,7 @@ protected:
|
|||||||
/// rejected lease update.
|
/// rejected lease update.
|
||||||
struct RejectedClient6 {
|
struct RejectedClient6 {
|
||||||
std::vector<uint8_t> duid_;
|
std::vector<uint8_t> duid_;
|
||||||
|
int64_t expire_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Multi index container holding information about the clients
|
/// @brief Multi index container holding information about the clients
|
||||||
@@ -1018,7 +1112,11 @@ protected:
|
|||||||
typedef boost::multi_index_container<
|
typedef boost::multi_index_container<
|
||||||
RejectedClient6,
|
RejectedClient6,
|
||||||
boost::multi_index::indexed_by<
|
boost::multi_index::indexed_by<
|
||||||
ClientIdent6<RejectedClient6>
|
ClientIdent6<RejectedClient6>,
|
||||||
|
boost::multi_index::ordered_non_unique<
|
||||||
|
boost::multi_index::member<RejectedClient6, int64_t,
|
||||||
|
&RejectedClient6::expire_>
|
||||||
|
>
|
||||||
>
|
>
|
||||||
> RejectedClients6;
|
> RejectedClients6;
|
||||||
|
|
||||||
|
@@ -137,6 +137,10 @@ public:
|
|||||||
/// rejected leases.
|
/// rejected leases.
|
||||||
void reportRejectedLeasesV6InvalidValuesTest();
|
void reportRejectedLeasesV6InvalidValuesTest();
|
||||||
|
|
||||||
|
/// @brief Test that old rejected lease updates are discarded while
|
||||||
|
/// getting the rejected lease updates count.
|
||||||
|
void getRejectedLeaseUpdatesCountFromContainerTest();
|
||||||
|
|
||||||
/// @brief Returns test heartbeat implementation.
|
/// @brief Returns test heartbeat implementation.
|
||||||
///
|
///
|
||||||
/// @return Pointer to heartbeat implementation function under test.
|
/// @return Pointer to heartbeat implementation function under test.
|
||||||
@@ -729,15 +733,24 @@ void
|
|||||||
CommunicationStateTest::reportRejectedLeasesV4Test() {
|
CommunicationStateTest::reportRejectedLeasesV4Test() {
|
||||||
// Initially, there should be no rejected leases.
|
// Initially, there should be no rejected leases.
|
||||||
EXPECT_EQ(0, state_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(0, state_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject lease update.
|
// Reject lease update.
|
||||||
auto msg = createMessage4(DHCPREQUEST, 1, 0, 0);
|
auto msg = createMessage4(DHCPREQUEST, 1, 0, 0);
|
||||||
state_.reportRejectedLeaseUpdate(msg);
|
state_.reportRejectedLeaseUpdate(msg);
|
||||||
EXPECT_EQ(1, state_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(1, state_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject another lease update.
|
// Reject another lease update.
|
||||||
msg = createMessage4(DHCPREQUEST, 2, 0, 0);
|
msg = createMessage4(DHCPREQUEST, 2, 0, 0);
|
||||||
state_.reportRejectedLeaseUpdate(msg);
|
state_.reportRejectedLeaseUpdate(msg);
|
||||||
EXPECT_EQ(2, state_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(2, state_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
|
// Reject a lease with a short (zero) lease lifetime.
|
||||||
|
// This lease should be discarded when we call the
|
||||||
|
// getRejectedLeaseUpdatesCount().
|
||||||
|
msg = createMessage4(DHCPREQUEST, 3, 0, 0);
|
||||||
|
state_.reportRejectedLeaseUpdate(msg, 0);
|
||||||
|
EXPECT_EQ(2, state_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject lease update for a client using the same MAC
|
// Reject lease update for a client using the same MAC
|
||||||
// address but different client identifier. It should
|
// address but different client identifier. It should
|
||||||
// be treated as a different lease.
|
// be treated as a different lease.
|
||||||
@@ -779,6 +792,9 @@ CommunicationStateTest::reportSuccessfulLeasesV4Test() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
CommunicationStateTest::reportRejectedLeasesV4InvalidValuesTest() {
|
CommunicationStateTest::reportRejectedLeasesV4InvalidValuesTest() {
|
||||||
|
// Populate one valid update. Without it our functions under test
|
||||||
|
// would return early.
|
||||||
|
state_.reportRejectedLeaseUpdate(createMessage4(DHCPREQUEST, 1, 0, 0));
|
||||||
// Using DHCPv6 message in the DHCPv4 context is a programming
|
// Using DHCPv6 message in the DHCPv4 context is a programming
|
||||||
// error and deserves an exception.
|
// error and deserves an exception.
|
||||||
auto msg = createMessage6(DHCPV6_REQUEST, 1, 0);
|
auto msg = createMessage6(DHCPV6_REQUEST, 1, 0);
|
||||||
@@ -790,18 +806,29 @@ void
|
|||||||
CommunicationStateTest::reportRejectedLeasesV6Test() {
|
CommunicationStateTest::reportRejectedLeasesV6Test() {
|
||||||
// Initially, there should be no rejected leases.
|
// Initially, there should be no rejected leases.
|
||||||
EXPECT_EQ(0, state6_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(0, state6_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject lease update.
|
// Reject lease update.
|
||||||
auto msg = createMessage6(DHCPV6_SOLICIT, 1, 0);
|
auto msg = createMessage6(DHCPV6_REQUEST, 1, 0);
|
||||||
state6_.reportRejectedLeaseUpdate(msg);
|
state6_.reportRejectedLeaseUpdate(msg);
|
||||||
EXPECT_EQ(1, state6_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(1, state6_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject another lease update.
|
// Reject another lease update.
|
||||||
msg = createMessage6(DHCPV6_SOLICIT, 2, 0);
|
msg = createMessage6(DHCPV6_REQUEST, 2, 0);
|
||||||
state6_.reportRejectedLeaseUpdate(msg);
|
state6_.reportRejectedLeaseUpdate(msg);
|
||||||
EXPECT_EQ(2, state6_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(2, state6_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
|
// Reject a lease with a short (zero) lease lifetime.
|
||||||
|
// This lease should be discarded when we call the
|
||||||
|
// getRejectedLeaseUpdatesCount().
|
||||||
|
msg = createMessage6(DHCPV6_REQUEST, 3, 0);
|
||||||
|
state6_.reportRejectedLeaseUpdate(msg, 0);
|
||||||
|
EXPECT_EQ(2, state6_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Reject it again. It should not affect the counter.
|
// Reject it again. It should not affect the counter.
|
||||||
msg = createMessage6(DHCPV6_SOLICIT, 2, 0);
|
msg = createMessage6(DHCPV6_REQUEST, 2, 0);
|
||||||
state6_.reportRejectedLeaseUpdate(msg);
|
state6_.reportRejectedLeaseUpdate(msg);
|
||||||
EXPECT_EQ(2, state6_.getRejectedLeaseUpdatesCount());
|
EXPECT_EQ(2, state6_.getRejectedLeaseUpdatesCount());
|
||||||
|
|
||||||
// Clear rejected lease updates and make sure they
|
// Clear rejected lease updates and make sure they
|
||||||
// are now 0.
|
// are now 0.
|
||||||
state6_.clearRejectedLeaseUpdates();
|
state6_.clearRejectedLeaseUpdates();
|
||||||
@@ -838,6 +865,9 @@ CommunicationStateTest::reportSuccessfulLeasesV6Test() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
CommunicationStateTest::reportRejectedLeasesV6InvalidValuesTest() {
|
CommunicationStateTest::reportRejectedLeasesV6InvalidValuesTest() {
|
||||||
|
// Populate one valid update. Without it our functions under test
|
||||||
|
// would return early.
|
||||||
|
state6_.reportRejectedLeaseUpdate(createMessage6(DHCPV6_REQUEST, 1, 0));
|
||||||
// Using DHCPv4 message in the DHCPv6 context is a programming
|
// Using DHCPv4 message in the DHCPv6 context is a programming
|
||||||
// error and deserves an exception.
|
// error and deserves an exception.
|
||||||
auto msg0 = createMessage4(DHCPREQUEST, 1, 1, 0);
|
auto msg0 = createMessage4(DHCPREQUEST, 1, 1, 0);
|
||||||
@@ -850,6 +880,49 @@ CommunicationStateTest::reportRejectedLeasesV6InvalidValuesTest() {
|
|||||||
EXPECT_FALSE(state6_.reportSuccessfulLeaseUpdate(msg1));
|
EXPECT_FALSE(state6_.reportSuccessfulLeaseUpdate(msg1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CommunicationStateTest::getRejectedLeaseUpdatesCountFromContainerTest() {
|
||||||
|
// Create a simple multi index container with two indexes. The
|
||||||
|
// first index is on the ordinal number to distinguish between
|
||||||
|
// different entries. The second index is on the expire_ field
|
||||||
|
// that is identical to the expire_ field in the RejectedClients4
|
||||||
|
// and RejectedClients6 containers.
|
||||||
|
struct Entry {
|
||||||
|
int64_t ordinal_;
|
||||||
|
int64_t expire_;
|
||||||
|
};
|
||||||
|
typedef boost::multi_index_container<
|
||||||
|
Entry,
|
||||||
|
boost::multi_index::indexed_by<
|
||||||
|
boost::multi_index::ordered_unique<
|
||||||
|
boost::multi_index::member<Entry, int64_t,
|
||||||
|
&Entry::ordinal_>
|
||||||
|
>,
|
||||||
|
boost::multi_index::ordered_non_unique<
|
||||||
|
boost::multi_index::member<Entry, int64_t,
|
||||||
|
&Entry::expire_>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
> Entries;
|
||||||
|
// Add many entries to the container. Odd entries have lifetime
|
||||||
|
// expiring in the future. Even entries have lifetimes expiring in
|
||||||
|
// the past.
|
||||||
|
Entries entries;
|
||||||
|
for (auto i = 0; i < 1000; i++) {
|
||||||
|
entries.insert({i, time(NULL) + (i % 2 ? 100 + i : -1 - i)});
|
||||||
|
}
|
||||||
|
// Get the count of valid entries. It should remove the expiring
|
||||||
|
// entries.
|
||||||
|
auto valid_entries_count = state_.getRejectedLeaseUpdatesCountFromContainer(entries);
|
||||||
|
EXPECT_EQ(500, valid_entries_count);
|
||||||
|
EXPECT_EQ(500, entries.size());
|
||||||
|
|
||||||
|
// Validate that we removed expired entries, not the valid ones.
|
||||||
|
for (auto entry : entries) {
|
||||||
|
EXPECT_EQ(1, entry.ordinal_ % 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(CommunicationStateTest, partnerStateTest) {
|
TEST_F(CommunicationStateTest, partnerStateTest) {
|
||||||
partnerStateTest();
|
partnerStateTest();
|
||||||
}
|
}
|
||||||
@@ -1057,4 +1130,8 @@ TEST_F(CommunicationStateTest, reportRejectedLeasesV6InvalidValuesTestMultiThrea
|
|||||||
reportRejectedLeasesV6InvalidValuesTest();
|
reportRejectedLeasesV6InvalidValuesTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CommunicationStateTest, getRejectedLeaseUpdatesCountFromContainerTest) {
|
||||||
|
getRejectedLeaseUpdatesCountFromContainerTest();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,7 @@ public:
|
|||||||
using StateType::my_time_at_skew_;
|
using StateType::my_time_at_skew_;
|
||||||
using StateType::partner_time_at_skew_;
|
using StateType::partner_time_at_skew_;
|
||||||
using StateType::unsent_update_count_;
|
using StateType::unsent_update_count_;
|
||||||
|
using StateType::getRejectedLeaseUpdatesCountFromContainer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Type of the NakedCommunicationState for DHCPv4.
|
/// @brief Type of the NakedCommunicationState for DHCPv4.
|
||||||
|
Reference in New Issue
Block a user