return (0);
}
+/// @brief lease4_expire callout implementation.
+///
+/// @param handle callout handle.
+int lease4_expire(CalloutHandle& handle) {
+ CalloutHandle::CalloutNextStep status = handle.getStatus();
+ if (status == CalloutHandle::NEXT_STEP_SKIP) {
+ return (0);
+ }
+
+ try {
+ impl->lease4Expire(handle);
+ } catch (const std::exception& ex) {
+ LOG_ERROR(ha_logger, HA_LEASE4_EXPIRE_FAILED)
+ .arg(ex.what());
+ return (1);
+ }
+
+ return (0);
+}
/// @brief dhcp6_srv_configured callout implementation.
///
return (0);
}
+/// @brief lease6_expire callout implementation.
+///
+/// @param handle callout handle.
+int lease6_expire(CalloutHandle& handle) {
+ CalloutHandle::CalloutNextStep status = handle.getStatus();
+ if (status == CalloutHandle::NEXT_STEP_SKIP) {
+ return (0);
+ }
+
+ try {
+ impl->lease6Expire(handle);
+ } catch (const std::exception& ex) {
+ LOG_ERROR(ha_logger, HA_LEASE6_EXPIRE_FAILED)
+ .arg(ex.what());
+ return (1);
+ }
+
+ return (0);
+}
+
/// @brief command_processed callout implementation.
///
/// @param handle callout handle.
#include <cc/command_interpreter.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
callout_handle.setArgument("peers_to_update", peers_to_update);
}
+void
+HAImpl::lease4Expire(CalloutHandle& callout_handle) {
+ Lease4Ptr lease4;
+ callout_handle.getArgument("lease4", lease4);
+
+ // If there are multiple relationships we need to take a detour and find
+ // a subnet the lease belongs to. The subnet will contain the information
+ // required to select appropriate HA service.
+ HAServicePtr service;
+ if (services_->hasMultiple()) {
+ auto subnet4 = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease4->subnet_id_);
+ if (!subnet4) {
+ // No subnet means that we possibly have some stale leases that don't
+ // really belong to us. Therefore, there we return early and rely on the
+ // DHCP server to reclaim them. The HA hook has no way to juristiction here.
+ return;
+ }
+
+ std::string server_name;
+ try {
+ server_name = HAConfig::getSubnetServerName(subnet4);
+ if (server_name.empty()) {
+ // Again, this subnet has no hint for HA where our lease belongs.
+ // We have to rely on the server to run reclamation of this lease.
+ return;
+ }
+ } catch (...) {
+ // Someone has tried to configure the hint for HA in the subnet but
+ // it was poorly specified. We will log an error and leave again.
+ LOG_ERROR(ha_logger, HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME)
+ .arg(lease4->addr_.toText())
+ .arg(subnet4->toText());
+ return;
+ }
+ service = services_->get(server_name);
+
+ } else {
+ service = services_->get();
+ }
+
+ if (!service) {
+ // This is highly unlikely but better handle null pointers.
+ return;
+ }
+
+ if (!shouldReclaim(service, lease4)) {
+ // While the server is in the terminated state it has to be careful about
+ // reclaiming the leases to avoid conflicting DNS updates with a server that
+ // owns the lease. This lease apparently belongs to another server, so we
+ // should not reclaim it.
+ LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE4_EXPIRE_RECLAMATION_SKIP)
+ .arg(lease4->addr_.toText());
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ return;
+ }
+}
+
void
HAImpl::buffer6Receive(hooks::CalloutHandle& callout_handle) {
// If there are multiple relationships, the HA-specific processing is
callout_handle.setStatus(CalloutHandle::NEXT_STEP_PARK);
}
+void
+HAImpl::lease6Expire(CalloutHandle& callout_handle) {
+ Lease6Ptr lease6;
+ callout_handle.getArgument("lease6", lease6);
+
+ // If there are multiple relationships we need to take a detour and find
+ // a subnet the lease belongs to. The subnet will contain the information
+ // required to select appropriate HA service.
+ HAServicePtr service;
+ if (services_->hasMultiple()) {
+ auto subnet6 = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease6->subnet_id_);
+ if (!subnet6) {
+ // No subnet means that we possibly have some stale leases that don't
+ // really belong to us. Therefore, there we return early and rely on the
+ // DHCP server to reclaim them. The HA hook has no way to juristiction here.
+ return;
+ }
+
+ std::string server_name;
+ try {
+ server_name = HAConfig::getSubnetServerName(subnet6);
+ if (server_name.empty()) {
+ // Again, this subnet has no hint for HA where our lease belongs.
+ // We have to rely on the server to run reclamation of this lease.
+ return;
+ }
+ } catch (...) {
+ // Someone has tried to configure the hint for HA in the subnet but
+ // it was poorly specified. We will log an error and leave again.
+ LOG_ERROR(ha_logger, HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME)
+ .arg(lease6->addr_.toText())
+ .arg(subnet6->toText());
+ return;
+ }
+ service = services_->get(server_name);
+
+ } else {
+ service = services_->get();
+ }
+
+ if (!service) {
+ // This is highly unlikely but better handle null pointers.
+ return;
+ }
+
+ if (!shouldReclaim(service, lease6)) {
+ // While the server is in the terminated state it has to be careful about
+ // reclaiming the leases to avoid conflicting DNS updates with a server that
+ // owns the lease. This lease apparently belongs to another server, so we
+ // should not reclaim it.
+ LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE6_EXPIRE_RECLAMATION_SKIP)
+ .arg(lease6->addr_.toText());
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ return;
+ }
+}
+
void
HAImpl::commandProcessed(hooks::CalloutHandle& callout_handle) {
std::string command_name;
return (service);
}
+bool
+HAImpl::shouldReclaim(const HAServicePtr& service, const dhcp::Lease4Ptr& lease4) const {
+ return (service->shouldReclaim(lease4));
+}
+
+bool
+HAImpl::shouldReclaim(const HAServicePtr& service, const dhcp::Lease6Ptr& lease6) const {
+ return (service->shouldReclaim(lease6));
+}
+
+
} // end of namespace isc::ha
} // end of namespace isc
const HAServerType& server_type);
/// @brief Destructor.
- ~HAImpl();
+ virtual ~HAImpl();
/// @brief Returns a configuration for the first relationship.
///
/// @param callout_handle Callout handle provided to the callout.
void lease4ServerDecline(hooks::CalloutHandle& callout_handle);
+ /// @brief Implementation of the "lease4_expire" callout.
+ ///
+ /// @param callout_handle Callout handle provided to the callout.
+ void lease4Expire(hooks::CalloutHandle& callout_handle);
+
/// @brief Implementation of the "buffer6_receive" callout.
///
/// This callout uses HA service to check if the query should be processed
/// @param callout_handle Callout handle provided to the callout.
void leases6Committed(hooks::CalloutHandle& callout_handle);
+ /// @brief Implementation of the "lease6_expire" callout.
+ ///
+ /// @param callout_handle Callout handle provided to the callout.
+ void lease6Expire(hooks::CalloutHandle& callout_handle);
+
/// @brief Implementation of the "command_processed" callout.
///
/// It adds the HA servers information to "status-get" command responses by
protected:
+ /// @brief Checks if the lease should be reclaimed by this server.
+ ///
+ /// The lease must not be reclaimed by the server when the server is in the
+ /// terminated state and the lease belongs to another server (per load balancing
+ /// algorithm or when it is a standby server).
+ ///
+ /// This function is virtual so that it can be derived and mocked in the tests.
+ ///
+ /// @param service pointer to the HA service to which the lease belongs.
+ /// @param lease4 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv4 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ virtual bool shouldReclaim(const HAServicePtr& service, const dhcp::Lease4Ptr& lease4) const;
+
+ /// @brief Checks if the lease should be reclaimed by this server.
+ ///
+ /// The lease must not be reclaimed by the server when the server is in the
+ /// terminated state and the lease belongs to another server (per load balancing
+ /// algorithm or when it is a standby server).
+ ///
+ /// This function is virtual so that it can be derived and mocked in the tests.
+ ///
+ /// @param service pointer to the HA service to which the lease belongs.
+ /// @param lease6 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv6 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ virtual bool shouldReclaim(const HAServicePtr& service, const dhcp::Lease6Ptr& lease6) const;
+
/// @brief The hook I/O service.
isc::asiolink::IOServicePtr io_service_;
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY = "HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY";
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_HOT_STANDBY = "HA_INVALID_PARTNER_STATE_HOT_STANDBY";
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_LOAD_BALANCING = "HA_INVALID_PARTNER_STATE_LOAD_BALANCING";
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_FAILED = "HA_LEASE4_EXPIRE_FAILED";
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME = "HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME";
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_RECLAMATION_SKIP = "HA_LEASE4_EXPIRE_RECLAMATION_SKIP";
extern const isc::log::MessageID HA_LEASE4_SERVER_DECLINE_FAILED = "HA_LEASE4_SERVER_DECLINE_FAILED";
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_FAILED = "HA_LEASE6_EXPIRE_FAILED";
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME = "HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME";
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_RECLAMATION_SKIP = "HA_LEASE6_EXPIRE_RECLAMATION_SKIP";
extern const isc::log::MessageID HA_LEASES4_COMMITTED_FAILED = "HA_LEASES4_COMMITTED_FAILED";
extern const isc::log::MessageID HA_LEASES4_COMMITTED_NOTHING_TO_UPDATE = "HA_LEASES4_COMMITTED_NOTHING_TO_UPDATE";
extern const isc::log::MessageID HA_LEASES4_COMMITTED_NO_RELATIONSHIP = "HA_LEASES4_COMMITTED_NO_RELATIONSHIP";
extern const isc::log::MessageID HA_LEASE_UPDATE_REJECTS_CAUSED_TERMINATION = "HA_LEASE_UPDATE_REJECTS_CAUSED_TERMINATION";
extern const isc::log::MessageID HA_LOAD_BALANCING_DUID_MISSING = "HA_LOAD_BALANCING_DUID_MISSING";
extern const isc::log::MessageID HA_LOAD_BALANCING_IDENTIFIER_MISSING = "HA_LOAD_BALANCING_IDENTIFIER_MISSING";
+extern const isc::log::MessageID HA_LOAD_BALANCING_LEASE_DUID_MISSING = "HA_LOAD_BALANCING_LEASE_DUID_MISSING";
+extern const isc::log::MessageID HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING = "HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING";
extern const isc::log::MessageID HA_LOCAL_DHCP_DISABLE = "HA_LOCAL_DHCP_DISABLE";
extern const isc::log::MessageID HA_LOCAL_DHCP_ENABLE = "HA_LOCAL_DHCP_ENABLE";
extern const isc::log::MessageID HA_MAINTENANCE_CANCEL_HANDLER_FAILED = "HA_MAINTENANCE_CANCEL_HANDLER_FAILED";
"HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY", "%1: partner is in the communication-recovery state unexpectedly",
"HA_INVALID_PARTNER_STATE_HOT_STANDBY", "%1: partner is in the hot-standby state unexpectedly",
"HA_INVALID_PARTNER_STATE_LOAD_BALANCING", "%1: partner is in the load-balancing state unexpectedly",
+ "HA_LEASE4_EXPIRE_FAILED", "lease4_expire callout failed: %1",
+ "HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME", "%1: invalid ha-server-name value for subnet %2",
+ "HA_LEASE4_EXPIRE_RECLAMATION_SKIP", "%1: skipping reclamation of the lease that belongs to a partner",
"HA_LEASE4_SERVER_DECLINE_FAILED", "lease4_server_decline callout failed: %1",
+ "HA_LEASE6_EXPIRE_FAILED", "lease4_expire callout failed: %1",
+ "HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME", "%1: invalid ha-server-name value for subnet %2",
+ "HA_LEASE6_EXPIRE_RECLAMATION_SKIP", "%1: skipping reclamation of the lease that belongs to a partner",
"HA_LEASES4_COMMITTED_FAILED", "leases4_committed callout failed: %1",
"HA_LEASES4_COMMITTED_NOTHING_TO_UPDATE", "%1: leases4_committed callout was invoked without any leases",
"HA_LEASES4_COMMITTED_NO_RELATIONSHIP", "%1: HA relationship not found: %2",
"HA_LEASE_UPDATE_REJECTS_CAUSED_TERMINATION", "%1: too many rejected lease updates cause the HA service to terminate",
"HA_LOAD_BALANCING_DUID_MISSING", "%1: load balancing failed for the DHCPv6 message (transaction id: %2) because DUID is missing",
"HA_LOAD_BALANCING_IDENTIFIER_MISSING", "%1: load balancing failed for the DHCPv4 message (transaction id: %2) because HW address and client identifier are missing",
+ "HA_LOAD_BALANCING_LEASE_DUID_MISSING", "%1: load balancing failed for the DHCPv6 lease %2 because DUID is missing",
+ "HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING", "%1: load balancing failed for the DHCPv4 lease %2 because HW address and client identifier are missing",
"HA_LOCAL_DHCP_DISABLE", "local DHCP service is disabled while the %1 is in the %2 state",
"HA_LOCAL_DHCP_ENABLE", "local DHCP service is enabled while the %1 is in the %2 state",
"HA_MAINTENANCE_CANCEL_HANDLER_FAILED", "ha-maintenance-cancel command failed: %1",
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY;
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_HOT_STANDBY;
extern const isc::log::MessageID HA_INVALID_PARTNER_STATE_LOAD_BALANCING;
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_FAILED;
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME;
+extern const isc::log::MessageID HA_LEASE4_EXPIRE_RECLAMATION_SKIP;
extern const isc::log::MessageID HA_LEASE4_SERVER_DECLINE_FAILED;
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_FAILED;
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME;
+extern const isc::log::MessageID HA_LEASE6_EXPIRE_RECLAMATION_SKIP;
extern const isc::log::MessageID HA_LEASES4_COMMITTED_FAILED;
extern const isc::log::MessageID HA_LEASES4_COMMITTED_NOTHING_TO_UPDATE;
extern const isc::log::MessageID HA_LEASES4_COMMITTED_NO_RELATIONSHIP;
extern const isc::log::MessageID HA_LEASE_UPDATE_REJECTS_CAUSED_TERMINATION;
extern const isc::log::MessageID HA_LOAD_BALANCING_DUID_MISSING;
extern const isc::log::MessageID HA_LOAD_BALANCING_IDENTIFIER_MISSING;
+extern const isc::log::MessageID HA_LOAD_BALANCING_LEASE_DUID_MISSING;
+extern const isc::log::MessageID HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING;
extern const isc::log::MessageID HA_LOCAL_DHCP_DISABLE;
extern const isc::log::MessageID HA_LOCAL_DHCP_ENABLE;
extern const isc::log::MessageID HA_MAINTENANCE_CANCEL_HANDLER_FAILED;
by the partner exceeds the limit set with max-rejected-lease-updates
configuration parameter.
+% HA_LEASE4_EXPIRE_FAILED lease4_expire callout failed: %1
+This error message is issued when the callout for the lease4_expire hook
+point failed. This includes unexpected errors like wrong arguments provided to
+the callout by the DHCP server (unlikely internal server error).
+The argument contains a reason for the error.
+
+% HA_LEASE4_EXPIRE_INVALID_HA_SERVER_NAME %1: invalid ha-server-name value for subnet %2
+This error message is issued when the reclaimed DHCPv4 lease belongs to
+a subnet which includes ha-server-name value in the user-context but this
+value is not a string or is empty. It is a server's misconifguration.
+The first argument holds the lease information. The second argument is a
+subnet prefix.
+
+% HA_LEASE4_EXPIRE_RECLAMATION_SKIP %1: skipping reclamation of the lease that belongs to a partner
+Logged at debug log level 40.
+This debug message is issued when the server is in the terminated state and
+skips reclamation of the lease that was probably allocated by another server,
+or is maintained by the other server while the servers are in the HA terminated
+state. The argument is the lease address.
+
+% HA_LEASE6_EXPIRE_FAILED lease4_expire callout failed: %1
+This error message is issued when the callout for the lease4_expire hook
+point failed. This includes unexpected errors like wrong arguments provided to
+the callout by the DHCP server (unlikely internal server error).
+The argument contains a reason for the error.
+
+% HA_LEASE6_EXPIRE_INVALID_HA_SERVER_NAME %1: invalid ha-server-name value for subnet %2
+This error message is issued when the reclaimed DHCPv6 lease belongs to
+a subnet which includes ha-server-name value in the user-context but this
+value is not a string or is empty. It is a server's misconifguration.
+The first argument holds the lease information. The second argument is a
+subnet prefix.
+
+% HA_LEASE6_EXPIRE_RECLAMATION_SKIP %1: skipping reclamation of the lease that belongs to a partner
+Logged at debug log level 40.
+This debug message is issued when the server is in the terminated state and
+skips reclamation of the lease that was probably allocated by another server,
+or is maintained by the other server while the servers are in the HA terminated
+state. The argument is the lease address.
+
% HA_LOAD_BALANCING_DUID_MISSING %1: load balancing failed for the DHCPv6 message (transaction id: %2) because DUID is missing
Logged at debug log level 40.
This debug message is issued when the HA hook library was unable to load
HW address was included in the query. The query will be dropped. The
sole argument contains transaction id.
+% HA_LOAD_BALANCING_LEASE_DUID_MISSING %1: load balancing failed for the DHCPv6 lease %2 because DUID is missing
+Logged at debug log level 40.
+This debug message is issued when the HA hook library was unable to load
+balance a reclaimed DHCPv6 lease because client identifier was not included
+found in the lease.
+
+% HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING %1: load balancing failed for the DHCPv4 lease %2 because HW address and client identifier are missing
+Logged at debug log level 40.
+This debug message is issued when the HA hook library was unable to load
+balance a reclaimed DHCPv4 lease because neither client identifier nor
+HW address was included in the query.
+
% HA_LOCAL_DHCP_DISABLE local DHCP service is disabled while the %1 is in the %2 state
This informational message is issued to indicate that the local DHCP service
is disabled because the server remains in a state in which the server
return (in_scope);
}
+bool
+HAService::shouldReclaim(const dhcp::Lease4Ptr& lease4) const {
+ return (shouldReclaimInternal(lease4));
+}
+
+bool
+HAService::shouldReclaim(const dhcp::Lease6Ptr& lease6) const {
+ return (shouldReclaimInternal(lease6));
+}
+
+template<typename LeasePtrType>
+bool
+HAService::shouldReclaimInternal(const LeasePtrType& lease) const {
+ return (getCurrState() != HA_TERMINATED_ST || query_filter_.inScope(lease));
+}
+
void
HAService::adjustNetworkState() {
std::string current_state_name = getStateLabel(getCurrState());
template<typename QueryPtrType>
bool inScopeInternal(QueryPtrType& query);
+public:
+
+ /// @brief Checks if the lease should be reclaimed by this server.
+ ///
+ /// The lease must not be reclaimed by the server when the server is in the
+ /// terminated state and the lease belongs to another server (per load balancing
+ /// algorithm or when it is a standby server).
+ ///
+ /// @param lease4 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv4 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ bool shouldReclaim(const dhcp::Lease4Ptr& lease4) const;
+
+ /// @brief Checks if the lease should be reclaimed by this server.
+ ///
+ /// The lease must not be reclaimed by the server when the server is in the
+ /// terminated state and the lease belongs to another server (per load balancing
+ /// algorithm or when it is a standby server).
+ ///
+ /// @param lease6 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv6 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ bool shouldReclaim(const dhcp::Lease6Ptr& lease6) const;
+
+private:
+
+ /// @brief Checks if the lease should be reclaimed by this server.
+ ///
+ /// The lease must not be reclaimed by the server when the server is in the
+ /// terminated state and the lease belongs to another server (per load balancing
+ /// algorithm or when it is a standby server).
+ ///
+ /// @tparam LeasePtrType type of the pointer to the DHCP lease.
+ /// @param lease pointer to the DHCP lease being reclaimed.
+ /// @return true if the DHCP lease should be reclaimed by this server instance,
+ /// false otherwise.
+ template<typename LeaseTypePtr>
+ bool shouldReclaimInternal(const LeaseTypePtr& lease) const;
+
public:
/// @brief Enables or disables network state depending on the served scopes.
QueryFilter::inScope(const dhcp::Pkt4Ptr& query4, std::string& scope_class) const {
if (MultiThreadingMgr::instance().getMode()) {
std::lock_guard<std::mutex> lock(*mutex_);
- return (inScopeInternal(query4, scope_class));
+ return (queryInScopeInternal(query4, scope_class));
} else {
- return (inScopeInternal(query4, scope_class));
+ return (queryInScopeInternal(query4, scope_class));
}
}
QueryFilter::inScope(const dhcp::Pkt6Ptr& query6, std::string& scope_class) const {
if (MultiThreadingMgr::instance().getMode()) {
std::lock_guard<std::mutex> lock(*mutex_);
- return (inScopeInternal(query6, scope_class));
+ return (queryInScopeInternal(query6, scope_class));
} else {
- return (inScopeInternal(query6, scope_class));
+ return (queryInScopeInternal(query6, scope_class));
}
}
template<typename QueryPtrType>
bool
-QueryFilter::inScopeInternal(const QueryPtrType& query,
+QueryFilter::queryInScopeInternal(const QueryPtrType& query,
std::string& scope_class) const {
if (!query) {
isc_throw(BadValue, "query must not be null");
}
-
// If it's not a type HA cares about, it's in scope for this peer.
if (!isHaType(query)) {
auto scope = peers_[0]->getName();
return ((candidate_server >= 0) && amServingScopeInternal(scope));
}
+bool
+QueryFilter::inScope(const Lease4Ptr& lease4) const {
+ if (MultiThreadingMgr::instance().getMode()) {
+ std::lock_guard<std::mutex> lock(*mutex_);
+ return (leaseInScopeInternal(lease4));
+ } else {
+ return (leaseInScopeInternal(lease4));
+ }
+}
+
+bool
+QueryFilter::inScope(const Lease6Ptr& lease6) const {
+ if (MultiThreadingMgr::instance().getMode()) {
+ std::lock_guard<std::mutex> lock(*mutex_);
+ return (leaseInScopeInternal(lease6));
+ } else {
+ return (leaseInScopeInternal(lease6));
+ }
+}
+
+template<typename LeasePtrType>
+bool
+QueryFilter::leaseInScopeInternal(const LeasePtrType& lease) const {
+ if (!lease) {
+ isc_throw(BadValue, "lease must not be null");
+ }
+
+ int candidate_server = 0;
+
+ // If we're doing load balancing we have to check if this query
+ // belongs to us or the partner. If it belongs to a partner but
+ // we're configured to serve this scope, we should accept it.
+ if (config_->getHAMode() == HAConfig::LOAD_BALANCING) {
+ candidate_server = loadBalance(lease);
+ // Malformed query received.
+ if (candidate_server < 0) {
+ return (false);
+ }
+ }
+
+ auto scope = peers_[candidate_server]->getName();
+ return ((candidate_server >= 0) && amServingScopeInternal(scope));
+}
+
int
QueryFilter::loadBalance(const dhcp::Pkt4Ptr& query4) const {
uint8_t lb_hash = 0;
return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
}
+int
+QueryFilter::loadBalance(const dhcp::Lease4Ptr& lease4) const {
+ uint8_t lb_hash = 0;
+ // Try to compute the hash by client identifier if the client
+ // identifier has been specified.
+ if (lease4->client_id_ && !lease4->client_id_->getClientId().empty()) {
+ auto const& client_id_key = lease4->client_id_->getClientId();
+ lb_hash = loadBalanceHash(&client_id_key[0], client_id_key.size());
+
+ } else {
+ // No client identifier available. Use the HW address instead.
+ HWAddrPtr hwaddr = lease4->hwaddr_;
+ if (hwaddr && !hwaddr->hwaddr_.empty()) {
+ lb_hash = loadBalanceHash(&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size());
+
+ } else {
+ // No client identifier and no HW address. Indicate an
+ // error.
+ LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LOAD_BALANCING_LEASE_IDENTIFIER_MISSING)
+ .arg(config_->getThisServerName())
+ .arg(lease4->addr_);
+ return (-1);
+ }
+ }
+
+ // The hash value modulo number of active servers gives an index
+ // of the server to process the packet.
+ return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
+}
+
+int
+QueryFilter::loadBalance(const dhcp::Lease6Ptr& lease6) const {
+ uint8_t lb_hash = 0;
+ // Compute the hash by DUID if the DUID.
+ auto duid = lease6->duid_;
+ if (duid && !duid->getDuid().empty()) {
+ auto const& duid_key = duid->getDuid();
+ lb_hash = loadBalanceHash(&duid_key[0], duid_key.size());
+
+ } else {
+ // No DUID. Indicate an error.
+ LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LOAD_BALANCING_LEASE_DUID_MISSING)
+ .arg(config_->getThisServerName())
+ .arg(lease6->addr_);
+ return (-1);
+ }
+
+ // The hash value modulo number of active servers gives an index
+ // of the server to process the packet.
+ return (active_servers_ > 0 ? static_cast<int>(lb_hash % active_servers_) : -1);
+}
+
uint8_t
QueryFilter::loadBalanceHash(const uint8_t* key, const size_t key_len) const {
uint8_t hash = static_cast<uint8_t>(key_len);
/// server, false otherwise.
bool inScope(const dhcp::Pkt6Ptr& query6, std::string& scope_class) const;
+ /// @brief Checks if this server should reclaim the DHCPv4 lease.
+ ///
+ /// This method is used to select DHCPv4 leases that are allocated by this
+ /// server during the normal operation. It is used when the servers in the
+ /// terminated state must reclaim expired leases. In this case each server
+ /// can only reclaim the leases it is responsible for to avoid the situation
+ /// that one of the servers reclaims a lease that another server allocates,
+ /// as it would cause conflicts of the DNS updates between the servers.
+ ///
+ /// @param lease4 pointer to the DHCPv4 lease instance.
+ ///
+ /// @return true if the specified query should be processed by this
+ /// server, false otherwise.
+ bool inScope(const dhcp::Lease4Ptr& lease4) const;
+
+ /// @brief Checks if this server should process the DHCPv6 query.
+ ///
+ /// This method is used to select DHCPv4 leases that are allocated by this
+ /// server during the normal operation. It is used when the servers in the
+ /// terminated state must reclaim expired leases. In this case each server
+ /// can only reclaim the leases it is responsible for to avoid the situation
+ /// that one of the servers reclaims a lease that another server allocates,
+ /// as it would cause conflicts of the DNS updates between the servers.
+ ///
+ /// @param lease6 pointer to the DHCPv6 lease instance.
+ ///
+ /// @return true if the specified query should be processed by this
+ /// server, false otherwise.
+ bool inScope(const dhcp::Lease6Ptr& lease6) const;
+
/// @brief Determines if a DHCPv4 query is a message type HA should process.
///
/// @param query4 DHCPv4 packet to test. Must not be null.
/// @return true if the specified query should be processed by this
/// server, false otherwise.
template<typename QueryPtrType>
- bool inScopeInternal(const QueryPtrType& query, std::string& scope_class) const;
+ bool queryInScopeInternal(const QueryPtrType& query, std::string& scope_class) const;
+
+ /// @brief Generic implementation of the @c inScope function for DHCPv4
+ /// and DHCPv6 leases.
+ ///
+ /// Should be called in a thread safe context.
+ ///
+ /// @tparam LeasePtrType type of the lease, i.e. DHCPv4 or DHCPv6 lease.
+ /// @param lease pointer to the DHCP lease instance.
+ ///
+ /// @return true if the specified lease should be reclaimed by this
+ /// server, false otherwise.
+ template<typename LeasePtrType>
+ bool leaseInScopeInternal(const LeasePtrType& lease) const;
protected:
/// no DUID.
int loadBalance(const dhcp::Pkt6Ptr& query6) const;
+ /// @brief Performs load balancing of the DHCPv4 leases.
+ ///
+ /// This method returns an index of the server configuration
+ /// held within @c peers_ vector. This points to a server
+ /// which should process the given lease. Currently, we only
+ /// support load balancing between two servers, therefore this
+ /// value should be 0 or 1.
+ ///
+ /// @param lease4 pointer to the DHCPv4 lease instance.
+ /// @return Index of the server which should process the lease. It
+ /// returns negative value if the lease is malformed, i.e. contains
+ /// no HW address and no client identifier.
+ int loadBalance(const dhcp::Lease4Ptr& lease4) const;
+
+ /// @brief Performs load balancing of the DHCPv6 leases.
+ ///
+ /// This method returns an index of the server configuration
+ /// held within @c peers_ vector. This points to a server
+ /// which should process the given lease. Currently, we only
+ /// support load balancing between two servers, therefore this
+ /// value should be 0 or 1.
+ ///
+ /// @param lease6 pointer to the DHCPv6 lease instance.
+ /// @return Index of the server which should process the lease. It
+ /// returns negative value if the lease is malformed, i.e. contains
+ /// no DUID.
+ int loadBalance(const dhcp::Lease6Ptr& lease6) const;
+
/// @brief Compute load balancing hash.
///
/// The load balancing hash is computed according to section 6
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/hwaddr.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/network_state.h>
#include <dhcpsrv/shared_network.h>
using HAImpl::config_;
using HAImpl::services_;
+
+ /// @brief Constructor.
+ TestHAImpl() :
+ HAImpl(), should_reclaim_dhcpv4_lease_(true),
+ should_reclaim_dhcpv6_lease_(true) { }
+
+ /// @brief Mock function checking if the lease should be reclaimed by this server.
+ ///
+ /// @param service pointer to the HA service to which the lease belongs.
+ /// @param lease4 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv4 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ virtual bool shouldReclaim(const HAServicePtr& service, const Lease4Ptr& lease4) const {
+ return (should_reclaim_dhcpv4_lease_);
+ }
+
+ /// @brief Mock function checking if the lease should be reclaimed by this server.
+ ///
+ /// @param service pointer to the HA service to which the lease belongs.
+ /// @param lease6 pointer to the DHCPv4 lease being reclaimed.
+ /// @return true if the DHCPv6 lease should be reclaimed by this server instance,
+ /// false otherwise.
+ virtual bool shouldReclaim(const HAServicePtr& service, const Lease6Ptr& lease6) const {
+ return (should_reclaim_dhcpv6_lease_);
+ }
+
+ /// @brief Custom value to be returned by the @c TestHAImpl::shouldReclaim function.
+ bool should_reclaim_dhcpv4_lease_;
+
+ /// @brief Custom value to be returned by the @c TestHAImpl::shouldReclaim function.
+ bool should_reclaim_dhcpv6_lease_;
};
/// @brief Test fixture class for @c HAImpl.
HAImplTest() {
// Clear statistics.
StatsMgr::instance().removeAll();
+ // Clear configuration.
+ CfgMgr::instance().clear();
}
/// @brief Destructor.
io_service_->stopAndPoll();
// Clear statistics.
StatsMgr::instance().removeAll();
+ // Clear configuration.
+ CfgMgr::instance().clear();
}
/// @brief Fetches the current value of the given statistic.
EXPECT_TRUE(callout_handle->getParkingLotHandlePtr()->drop(query6));
}
+// Tests lease4_expire callout implementation when the server is a hub
+// with multiple relationships.
+TEST_F(HAImplTest, lease4ExpireHub) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease4 = createLease4(std::vector<uint8_t>(6, 1));
+ lease4->addr_ = IOAddress("192.0.2.1");
+ lease4->subnet_id_ = 7;
+ callout_handle->setArgument("lease4", lease4);
+
+ // Create the subnet and include the server name in the context.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create("server3"));
+ auto subnet4 = Subnet4::create(IOAddress("192.0.2.0"), 24, 30, 40, 50, 7);
+ subnet4->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet4);
+ CfgMgr::instance().commit();
+
+ // Invoke the lease4_expire callout and expect that the lease reclamation
+ // will continue because the server is responsible for the lease.
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Mark the server not responsible for the lease. This time the reclamation
+ // should be skipped.
+ test_ha_impl_->should_reclaim_dhcpv4_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// with multiple relationships and no matching subnet has been configured.
+TEST_F(HAImplTest, lease4ExpireHubNoSubnet) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease4 = createLease4(std::vector<uint8_t>(6, 1));
+ lease4->addr_ = IOAddress("192.0.2.1");
+ lease4->subnet_id_ = 7;
+ callout_handle->setArgument("lease4", lease4);
+
+ test_ha_impl_->should_reclaim_dhcpv4_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// but the server name is empty.
+TEST_F(HAImplTest, lease4ExpireHubEmptyServerName) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease4 = createLease4(std::vector<uint8_t>(6, 1));
+ lease4->addr_ = IOAddress("192.0.2.1");
+ lease4->subnet_id_ = 7;
+ callout_handle->setArgument("lease4", lease4);
+
+ // Create the subnet and include empty server name in the context.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create(""));
+ auto subnet4 = Subnet4::create(IOAddress("192.0.2.0"), 24, 30, 40, 50, 7);
+ subnet4->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet4);
+ CfgMgr::instance().commit();
+
+ // Even though we intruct the server to skip the reclamation, the returned
+ // status should indicate otherwise because the callout returns early after
+ // checking that the server name is empty.
+ test_ha_impl_->should_reclaim_dhcpv4_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// but the server name has invalid type.
+TEST_F(HAImplTest, lease4ExpireHubInvalidServerName) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease4 = createLease4(std::vector<uint8_t>(6, 1));
+ lease4->addr_ = IOAddress("192.0.2.1");
+ lease4->subnet_id_ = 7;
+ callout_handle->setArgument("lease4", lease4);
+
+ // Create the subnet and include the server name argument. It has an
+ // invalid type.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create(123));
+ auto subnet4 = Subnet4::create(IOAddress("192.0.2.0"), 24, 30, 40, 50, 7);
+ subnet4->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet4);
+ CfgMgr::instance().commit();
+
+ // Even though we intruct the server to skip the reclamation, the returned
+ // status should indicate otherwise because the callout returns early after
+ // checking that the server name has invalid type.
+ test_ha_impl_->should_reclaim_dhcpv4_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// with multiple relationship.
+TEST_F(HAImplTest, lease4ExpireSingleService) {
+ ConstElementPtr ha_config = createValidJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease4 = createLease4(std::vector<uint8_t>(6, 1));
+ lease4->subnet_id_ = 7;
+ lease4->addr_ = IOAddress("192.0.2.1");
+ callout_handle->setArgument("lease4", lease4);
+
+ // Invoke the lease4_expire callout and expect that the lease reclamation
+ // will continue because the server is responsible for the lease.
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Mark the server not responsible for the lease. This time the reclamation
+ // should be skipped.
+ test_ha_impl_->should_reclaim_dhcpv4_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease4Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// with multiple relationships.
+TEST_F(HAImplTest, lease6ExpireHub) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv6));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease6 = createLease6(std::vector<uint8_t>(8, 1));
+ lease6->addr_ = IOAddress("2001:db8:1::1");
+ lease6->subnet_id_ = 7;
+ callout_handle->setArgument("lease6", lease6);
+
+ // Create the subnet and include the server name in the context.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create("server3"));
+ auto subnet6 = Subnet6::create(IOAddress("2001:db8:1::"), 64, 30, 40, 50, 60, 7);
+ subnet6->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet6);
+ CfgMgr::instance().commit();
+
+ // Invoke the lease6_expire callout and expect that the lease reclamation
+ // will continue because the server is responsible for the lease.
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Mark the server not responsible for the lease. This time the reclamation
+ // should be skipped.
+ test_ha_impl_->should_reclaim_dhcpv6_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle->getStatus());
+}
+
+// Tests lease6_expire callout implementation when the server is a hub
+// with multiple relationships and no matching subnet has been configured.
+TEST_F(HAImplTest, lease6ExpireHubNoSubnet) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv6));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease6 = createLease6(std::vector<uint8_t>(8, 1));
+ lease6->addr_ = IOAddress("2001:db8:1::1");
+ lease6->subnet_id_ = 7;
+ callout_handle->setArgument("lease6", lease6);
+
+ test_ha_impl_->should_reclaim_dhcpv6_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease6_expire callout implementation when the server is a hub
+// but the server name is empty.
+TEST_F(HAImplTest, lease6ExpireHubEmptyServerName) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv6));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease6 = createLease6(std::vector<uint8_t>(8, 1));
+ lease6->addr_ = IOAddress("2001:db8:1::1");
+ lease6->subnet_id_ = 7;
+ callout_handle->setArgument("lease6", lease6);
+
+ // Create the subnet and include the server name in the context.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create(""));
+ auto subnet6 = Subnet6::create(IOAddress("2001:db8:1::"), 64, 30, 40, 50, 60, 7);
+ subnet6->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet6);
+ CfgMgr::instance().commit();
+
+ // Even though we intruct the server to skip the reclamation, the returned
+ // status should indicate otherwise because the callout returns early after
+ // checking that the server name is empty.
+ test_ha_impl_->should_reclaim_dhcpv6_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// but the server name has invalid type.
+TEST_F(HAImplTest, lease6ExpireHubInvalidServerName) {
+ ConstElementPtr ha_config = createValidHubJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease6 = createLease6(std::vector<uint8_t>(8, 1));
+ lease6->addr_ = IOAddress("2001:db8:1::1");
+ lease6->subnet_id_ = 7;
+ callout_handle->setArgument("lease6", lease6);
+
+ // Create the subnet and include the server name argument. It has an
+ // invalid type.
+
+ // Create the subnet and include the server name in the context.
+ auto context = Element::createMap();
+ context->set("ha-server-name", Element::create(123));
+ auto subnet6 = Subnet6::create(IOAddress("2001:db8:1::"), 64, 30, 40, 50, 60, 7);
+ subnet6->setContext(context);
+ CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet6);
+ CfgMgr::instance().commit();
+
+ // Even though we intruct the server to skip the reclamation, the returned
+ // status should indicate otherwise because the callout returns early after
+ // checking that the server name has invalid type.
+ test_ha_impl_->should_reclaim_dhcpv6_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+}
+
+// Tests lease4_expire callout implementation when the server is a hub
+// with multiple relationship.
+TEST_F(HAImplTest, lease6ExpireSingleService) {
+ ConstElementPtr ha_config = createValidJsonConfiguration();
+
+ // Create implementation object and configure it.
+ test_ha_impl_.reset(new TestHAImpl());
+ test_ha_impl_->setIOService(io_service_);
+ ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
+
+ // Starting the service is required before any callouts.
+ NetworkStatePtr network_state(new NetworkState());
+ ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
+ HAServerType::DHCPv4));
+
+ // Create callout handle to be used for passing arguments to the
+ // callout.
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+ ASSERT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Create the lease
+ auto lease6 = createLease6(std::vector<uint8_t>(8, 1));
+ lease6->addr_ = IOAddress("2001:db8:1::1");
+ lease6->subnet_id_ = 7;
+ callout_handle->setArgument("lease6", lease6);
+
+ // Invoke the lease6_expire callout and expect that the lease reclamation
+ // will continue because the server is responsible for the lease.
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus());
+
+ // Mark the server not responsible for the lease. This time the reclamation
+ // should be skipped.
+ test_ha_impl_->should_reclaim_dhcpv6_lease_ = false;
+ ASSERT_NO_THROW(test_ha_impl_->lease6Expire(*callout_handle));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle->getStatus());
+}
+
// Tests ha-sync command handler with correct and incorrect arguments.
TEST_F(HAImplTest, synchronizeHandler) {
{
EXPECT_EQ(HA_COMMUNICATION_RECOVERY_ST, service_->getCurrState());
}
+// This test verifies that the service correctly identifies the leases that can
+// be reclaimed while the server is the primary.
+TEST_F(HAServiceStateMachineTest, shouldReclaimLease4HotStandbyThisPrimary) {
+ startService(createValidConfiguration(HAConfig::HOT_STANDBY));
+ service_->verboseTransition(HA_TERMINATED_ST);
+ service_->runModel(HAService::NOP_EVT);
+
+ Lease4Ptr lease4 = createLease4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
+ EXPECT_TRUE(service_->shouldReclaim(lease4));
+}
+
+// This test verifies that the service correctly identifies the leases that can
+// be reclaimed while the server is the standby.
+TEST_F(HAServiceStateMachineTest, shouldReclaimLease4HotStandbyThisStandby) {
+ HAConfigPtr valid_config = createValidConfiguration(HAConfig::HOT_STANDBY);
+ valid_config->getPeerConfig("server2")->setRole("standby");
+ valid_config->setThisServerName("server2");
+ startService(valid_config);
+ service_->verboseTransition(HA_TERMINATED_ST);
+ service_->runModel(HAService::NOP_EVT);
+
+ Lease4Ptr lease4 = createLease4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
+ EXPECT_FALSE(service_->shouldReclaim(lease4));
+}
+
+// This test verifies that the service correctly identifies the leases that can
+// be reclaimed while the server is the primary.
+TEST_F(HAServiceStateMachineTest, shouldReclaimLease6HotStandbyThisPrimary) {
+ startService(createValidConfiguration(HAConfig::HOT_STANDBY));
+ service_->verboseTransition(HA_TERMINATED_ST);
+ service_->runModel(HAService::NOP_EVT);
+
+ Lease6Ptr lease6 = createLease6(randomKey(10));
+ EXPECT_TRUE(service_->shouldReclaim(lease6));
+}
+
+// This test verifies that the service correctly identifies the leases that can
+// be reclaimed while the server is the standby.
+TEST_F(HAServiceStateMachineTest, shouldReclaimLease6HotStandbyThisStandby) {
+ HAConfigPtr valid_config = createValidConfiguration(HAConfig::HOT_STANDBY);
+ valid_config->getPeerConfig("server2")->setRole("standby");
+ valid_config->setThisServerName("server2");
+ startService(valid_config);
+ service_->verboseTransition(HA_TERMINATED_ST);
+ service_->runModel(HAService::NOP_EVT);
+
+ Lease6Ptr lease6 = createLease6(randomKey(10));
+ EXPECT_FALSE(service_->shouldReclaim(lease6));
+}
+
// Test scenario when a single lease4 update is sent successfully, parking is not
// employed.
TEST_F(HAServiceTest, successfulSendSingleLeaseUpdateWithoutParking) {
return (query6);
}
+Lease4Ptr
+HATest::createLease4(const std::vector<uint8_t>& hw_address_vec,
+ const std::vector<uint8_t>& client_id_vec) const {
+ HWAddrPtr hwaddr(new HWAddr(hw_address_vec, HTYPE_ETHER));
+ Lease4Ptr lease4(new Lease4(IOAddress("192.1.2.3"), hwaddr,
+ static_cast<const uint8_t*>(0), 0,
+ 60, 0, 1));
+ if (!client_id_vec.empty()) {
+ lease4->client_id_ = ClientIdPtr(new ClientId(client_id_vec));
+ }
+ return (lease4);
+}
+
+Lease6Ptr
+HATest::createLease6(const std::vector<uint8_t>& duid_vec) const {
+ DuidPtr duid(new DUID(duid_vec));
+ Lease6Ptr lease6(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::cafe"),
+ duid, 1234, 50, 60, 1));
+ return (lease6);
+}
+
Pkt6Ptr
HATest::createMessage6(const uint8_t msg_type, const uint8_t duid_seed,
const uint16_t elapsed_time) const {
/// @param duid DUI to be included in the query. It is used in load balancing.
dhcp::Pkt6Ptr createQuery6(const std::vector<uint8_t>& duid) const;
+ /// @brief Creates test DHCPv4 lease instance.
+ ///
+ /// @param hw_address_vec HW address to be included in the lease. It is used
+ /// in load balancing.
+ /// @param client_id_vec optional client identifier.
+ dhcp::Lease4Ptr createLease4(const std::vector<uint8_t>& hw_address_vec,
+ const std::vector<uint8_t>& client_id_vec =
+ std::vector<uint8_t>()) const;
+
+ /// @brief Creates test DHCPv6 lease instance.
+ ///
+ /// @param duid_vec DUID to be included in the query. It is used in load balancing.
+ dhcp::Lease6Ptr createLease6(const std::vector<uint8_t>& duid_vec) const;
+
/// @brief Generates simple DHCPv6 message.
///
/// @param msg_type DHCPv6 message type to be created.
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
+ // Create query and lease with with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
// If the query is in scope, increase the counter of packets in scope.
if (filter.inScope(query4, scope_class)) {
- ASSERT_EQ("HA_server1", scope_class);
- ASSERT_NE(scope_class, "HA_server2");
++in_scope;
+ EXPECT_EQ("HA_server1", scope_class);
+ EXPECT_TRUE(filter.inScope(lease4));
+ } else {
+ EXPECT_FALSE(filter.inScope(lease4));
}
+ return;
}
// We should have roughly 50/50 split of in scope and out of scope queries.
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
- // Every single query mist be in scope.
- ASSERT_TRUE(filter.inScope(query4, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
}
// However, the one that lacks HW address and client id should be out of
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random client identifier.
- Pkt4Ptr query4 = createQuery4(hw_address, randomKey(8));
+ // Create query and lease with random client identifier.
+ auto key = randomKey(8);
+ Pkt4Ptr query4 = createQuery4(hw_address, key);
+ Lease4Ptr lease4 = createLease4(hw_address, key);
// If the query is in scope, increase the counter of packets in scope.
if (filter.inScope(query4, scope_class)) {
- ASSERT_EQ("HA_server1", scope_class);
- ASSERT_NE(scope_class, "HA_server2");
++in_scope;
+ EXPECT_EQ("HA_server1", scope_class);
+ EXPECT_TRUE(filter.inScope(lease4));
+ } else {
+ EXPECT_FALSE(filter.inScope(lease4));
}
}
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random client identifier.
- Pkt4Ptr query4 = createQuery4(hw_address, randomKey(8));
- // Every single query mist be in scope.
- ASSERT_TRUE(filter.inScope(query4, scope_class));
+ // Create query and lease with random client identifier.
+ auto key = randomKey(8);
+ Pkt4Ptr query4 = createQuery4(hw_address, key);
+ Lease4Ptr lease4 = createLease4(hw_address, key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
}
}
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
// If the query is in scope, increase the counter of packets in scope.
if (filter.inScope(query4, scope_class)) {
- ASSERT_EQ("HA_server2", scope_class);
- ASSERT_NE(scope_class, "HA_server1");
++in_scope;
+ EXPECT_EQ("HA_server2", scope_class);
+ EXPECT_TRUE(filter.inScope(lease4));
+ } else {
+ EXPECT_FALSE(filter.inScope(lease4));
}
}
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
- // Every single query must be in scope.
- ASSERT_TRUE(filter.inScope(query4, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
}
}
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
- // None of the packets should be handlded by the backup server.
- ASSERT_FALSE(filter.inScope(query4, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
+ // None of the packets should be handled by the backup server.
+ EXPECT_FALSE(filter.inScope(query4, scope_class));
+ EXPECT_FALSE(filter.inScope(lease4));
}
// Simulate failover. Although, backup server never starts handling
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
- // Every single query must be in scope.
- ASSERT_TRUE(filter.inScope(query4, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
}
}
QueryFilter filter(config);
Pkt4Ptr query4 = createQuery4("11:22:33:44:55:66");
+ Lease4Ptr lease4 = createLease4(query4->getHWAddr()->hwaddr_);
// By default, only the primary server is active.
EXPECT_TRUE(filter.amServingScope("server1"));
// It should process its queries.
EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
// Simulate failover scenario, in which the active server detects a
// failure of the standby server. This doesn't change anything in how
EXPECT_TRUE(filter.inScope(query4, scope_class));
EXPECT_EQ("HA_server1", scope_class);
- EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_TRUE(filter.inScope(lease4));
}
void
QueryFilter filter(config);
Pkt4Ptr query4 = createQuery4("11:22:33:44:55:66");
+ Lease4Ptr lease4 = createLease4(query4->getHWAddr()->hwaddr_);
// The server2 doesn't process any queries by default. The whole
// traffic is processed by the server1.
EXPECT_FALSE(filter.inScope(query4, scope_class));
EXPECT_EQ("HA_server1", scope_class);
- EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_FALSE(filter.inScope(lease4));
// Simulate failover case whereby the standby server detects a
// failure of the active server.
EXPECT_TRUE(filter.inScope(query4, scope_class));
EXPECT_EQ("HA_server1", scope_class);
EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_TRUE(filter.inScope(lease4));
}
void
QueryFilter filter(config);
Pkt4Ptr query4 = createQuery4("11:22:33:44:55:66");
+ Lease4Ptr lease4 = createLease4(query4->getHWAddr()->hwaddr_);
// By default the backup server doesn't process any traffic.
EXPECT_FALSE(filter.amServingScope("server1"));
std::string scope_class;
EXPECT_FALSE(filter.inScope(query4, scope_class));
+ EXPECT_FALSE(filter.inScope(lease4));
// Simulate failover. Although, backup server never starts handling
// other server's traffic automatically, it can be manually instructed
EXPECT_FALSE(filter.amServingScope("server3"));
EXPECT_TRUE(filter.inScope(query4, scope_class));
+ EXPECT_TRUE(filter.inScope(lease4));
}
void
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random DUID.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
+ // Create query and lease with random DUID.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// If the query is in scope, increase the counter of packets in scope.
if (filter.inScope(query6, scope_class)) {
- ASSERT_EQ("HA_server1", scope_class);
- ASSERT_NE(scope_class, "HA_server2");
++in_scope;
+ EXPECT_EQ("HA_server1", scope_class);
+ EXPECT_TRUE(filter.inScope(lease6));
+ } else {
+ EXPECT_FALSE(filter.inScope(lease6));
}
}
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
- // Every single query mist be in scope.
- ASSERT_TRUE(filter.inScope(query6, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query6, scope_class));
+ EXPECT_TRUE(filter.inScope(lease6));
}
// However, the one that lacks DUID should be out of scope.
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
+ // Create query and lease with random HW address.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// If the query is in scope, increase the counter of packets in scope.
if (filter.inScope(query6, scope_class)) {
- ASSERT_EQ("HA_server2", scope_class);
- ASSERT_NE(scope_class, "HA_server1");
++in_scope;
+ EXPECT_EQ("HA_server2", scope_class);
+ EXPECT_TRUE(filter.inScope(lease6));
+ } else {
+ EXPECT_FALSE(filter.inScope(lease6));
}
}
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt6Ptr query6 = createQuery6(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
- // Every single query must be in scope.
- ASSERT_TRUE(filter.inScope(query6, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query6, scope_class));
+ EXPECT_TRUE(filter.inScope(lease6));
}
}
const unsigned queries_num = 65535;
std::string scope_class;
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
+ // Create query and lease with random HW address.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// None of the packets should be handlded by the backup server.
- ASSERT_FALSE(filter.inScope(query6, scope_class));
+ EXPECT_FALSE(filter.inScope(query6, scope_class));
+ EXPECT_FALSE(filter.inScope(lease6));
}
// Simulate failover. Although, backup server never starts handling
// Repeat the test, but this time all should be in scope.
for (unsigned i = 0; i < queries_num; ++i) {
- // Create query with random HW address.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
- // Every single query must be in scope.
- ASSERT_TRUE(filter.inScope(query6, scope_class));
+ // Create query and lease with random HW address.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
+ // Every single query and lease must be in scope.
+ EXPECT_TRUE(filter.inScope(query6, scope_class));
+ EXPECT_TRUE(filter.inScope(lease6));
}
}
QueryFilter filter(config);
- Pkt6Ptr query6 = createQuery6("01:02:11:22:33:44:55:66");
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// By default, only the primary server is active.
EXPECT_TRUE(filter.amServingScope("server1"));
// It should process its queries.
EXPECT_TRUE(filter.inScope(query6, scope_class));
+ EXPECT_TRUE(filter.inScope(lease6));
// Simulate failover scenario, in which the active server detects a
// failure of the standby server. This doesn't change anything in how
EXPECT_TRUE(filter.inScope(query6, scope_class));
EXPECT_EQ("HA_server1", scope_class);
- EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_TRUE(filter.inScope(lease6));
}
void
QueryFilter filter(config);
- Pkt6Ptr query6 = createQuery6("01:02:11:22:33:44:55:66");
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// The server2 doesn't process any queries by default. The whole
// traffic is processed by the server1.
EXPECT_FALSE(filter.inScope(query6, scope_class));
EXPECT_EQ("HA_server1", scope_class);
- EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_FALSE(filter.inScope(lease6));
// Simulate failover case whereby the standby server detects a
// failure of the active server.
EXPECT_TRUE(filter.inScope(query6, scope_class));
EXPECT_EQ("HA_server1", scope_class);
- EXPECT_NE(scope_class, "HA_server2");
+ EXPECT_TRUE(filter.inScope(lease6));
}
void
QueryFilter filter(config);
- Pkt6Ptr query6 = createQuery6(randomKey(10));
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
// By default the backup server doesn't process any traffic.
EXPECT_FALSE(filter.amServingScope("server1"));
std::string scope_class;
EXPECT_FALSE(filter.inScope(query6, scope_class));
+ EXPECT_FALSE(filter.inScope(lease6));
// Simulate failover. Although, backup server never starts handling
// other server's traffic automatically, it can be manually instructed
EXPECT_FALSE(filter.amServingScope("server3"));
EXPECT_TRUE(filter.inScope(query6, scope_class));
+ EXPECT_TRUE(filter.inScope(lease6));
}
void
for (unsigned i = 0; i < max_scope_tries; ++i) {
// Create query with random HW address.
std::string scope_class;
- Pkt4Ptr query4 = createQuery4(randomKey(HWAddr::ETHERNET_HWADDR_LEN));
+ auto key = randomKey(HWAddr::ETHERNET_HWADDR_LEN);
+ Pkt4Ptr query4 = createQuery4(key);
+ Lease4Ptr lease4 = createLease4(key);
// If the query is in scope then we're done.
if (filter.inScope(query4, scope_class)) {
- ASSERT_EQ("HA_server1", scope_class);
+ EXPECT_EQ("HA_server1", scope_class);
+ EXPECT_TRUE(filter.inScope(lease4));
server1_pkt = query4;
if (server2_pkt) {
break;
}
} else {
- ASSERT_EQ("HA_server2", scope_class);
+ EXPECT_EQ("HA_server2", scope_class);
+ EXPECT_FALSE(filter.inScope(lease4));
server2_pkt = query4;
if (server1_pkt) {
break;
// Create query with random HW address.
std::string scope_class;
- // Create query with random DUID.
- Pkt6Ptr query6 = createQuery6(randomKey(10));
+ // Create query and lease with random DUID.
+ auto key = randomKey(10);
+ Pkt6Ptr query6 = createQuery6(key);
+ Lease6Ptr lease6 = createLease6(key);
if (filter.inScope(query6, scope_class)) {
- ASSERT_EQ("HA_server1", scope_class);
+ EXPECT_EQ("HA_server1", scope_class);
+ EXPECT_TRUE(filter.inScope(lease6));
// In scope for server1, save it.
server1_pkt = query6;
if (server2_pkt) {
break;
}
} else {
- ASSERT_EQ("HA_server2", scope_class);
+ EXPECT_EQ("HA_server2", scope_class);
+ EXPECT_FALSE(filter.inScope(lease6));
// In scope for server2, save it.
server2_pkt = query6;
if (server1_pkt) {