2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-22 01:49:48 +00:00
2025-01-28 10:06:26 +01:00

486 lines
13 KiB
C++

// Copyright (C) 2017-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Functions accessed by the hooks framework use C linkage to avoid the name
// mangling that accompanies use of the C++ compiler as well as to avoid
// issues related to namespaces.
#include <config.h>
#include <ha_impl.h>
#include <ha_log.h>
#include <asiolink/io_service.h>
#include <asiolink/io_service_mgr.h>
#include <cc/command_interpreter.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/network_state.h>
#include <exceptions/exceptions.h>
#include <hooks/hooks.h>
#include <process/daemon.h>
#include <sstream>
#include <string>
namespace isc {
namespace ha {
HAImplPtr impl;
} // end of namespace isc::ha
} // end of namespace isc
using namespace isc::asiolink;
using namespace isc::config;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::ha;
using namespace isc::hooks;
using namespace isc::process;
using namespace std;
extern "C" {
/// @brief dhcp4_srv_configured callout implementation.
///
/// @param handle callout handle.
int dhcp4_srv_configured(CalloutHandle& handle) {
try {
isc::dhcp::NetworkStatePtr network_state;
handle.getArgument("network_state", network_state);
impl->startServices(network_state, HAServerType::DHCPv4);
IOServiceMgr::instance().registerIOService(impl->getIOService());
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_DHCP4_START_SERVICE_FAILED)
.arg(ex.what());
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
ostringstream os;
os << "Error: " << ex.what();
string error(os.str());
handle.setArgument("error", error);
return (1);
}
return (0);
}
/// @brief buffer4_receive callout implementation.
///
/// @param handle callout handle.
int buffer4_receive(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP) {
return (0);
}
try {
impl->buffer4Receive(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_BUFFER4_RECEIVE_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief subnet4_select callout implementation.
///
/// @param handle callout handle.
int subnet4_select(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP) {
return (0);
}
try {
impl->subnet4Select(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_SUBNET4_SELECT_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief leases4_committed callout implementation.
///
/// @param handle callout handle.
int leases4_committed(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP ||
status == CalloutHandle::NEXT_STEP_SKIP) {
return (0);
}
try {
impl->leases4Committed(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_LEASES4_COMMITTED_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief lease4_server_decline callout implementation.
///
/// @param handle callout handle.
int lease4_server_decline(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP ||
status == CalloutHandle::NEXT_STEP_SKIP) {
return (0);
}
try {
impl->lease4ServerDecline(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_LEASE4_SERVER_DECLINE_FAILED)
.arg(ex.what());
return (1);
}
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.
///
/// @param handle callout handle.
int dhcp6_srv_configured(CalloutHandle& handle) {
try {
isc::dhcp::NetworkStatePtr network_state;
handle.getArgument("network_state", network_state);
impl->startServices(network_state, HAServerType::DHCPv6);
IOServiceMgr::instance().registerIOService(impl->getIOService());
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_DHCP6_START_SERVICE_FAILED)
.arg(ex.what());
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
ostringstream os;
os << "Error: " << ex.what();
string error(os.str());
handle.setArgument("error", error);
return (1);
}
return (0);
}
/// @brief buffer6_receive callout implementation.
///
/// @param handle callout handle.
int buffer6_receive(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP ||
status == CalloutHandle::NEXT_STEP_SKIP) {
return (0);
}
try {
impl->buffer6Receive(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_BUFFER6_RECEIVE_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief subnet6_select callout implementation.
///
/// @param handle callout handle.
int subnet6_select(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP) {
return (0);
}
try {
impl->subnet6Select(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_SUBNET6_SELECT_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief leases6_committed callout implementation.
///
/// @param handle callout handle.
int leases6_committed(CalloutHandle& handle) {
CalloutHandle::CalloutNextStep status = handle.getStatus();
if (status == CalloutHandle::NEXT_STEP_DROP ||
status == CalloutHandle::NEXT_STEP_SKIP) {
return (0);
}
try {
impl->leases6Committed(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_LEASES6_COMMITTED_FAILED)
.arg(ex.what());
return (1);
}
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.
int command_processed(CalloutHandle& handle) {
try {
impl->commandProcessed(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_COMMAND_PROCESSED_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief Heartbeat command handler implementation.
int heartbeat_command(CalloutHandle& handle) {
try {
impl->heartbeatHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_HEARTBEAT_HANDLER_FAILED)
.arg(ex.what());
return (1);
}
return (0);
}
/// @brief ha-sync command handler implementation.
int sync_command(CalloutHandle& handle) {
try {
impl->synchronizeHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_SYNC_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-scopes command handler implementation.
int scopes_command(CalloutHandle& handle) {
try {
impl->scopesHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_SCOPES_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-continue command handler implementation.
int continue_command(CalloutHandle& handle) {
try {
impl->continueHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_CONTINUE_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-maintenance-notify command handler implementation.
int maintenance_notify_command(CalloutHandle& handle) {
try {
impl->maintenanceNotifyHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_MAINTENANCE_NOTIFY_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-maintenance-start command handler implementation.
int maintenance_start_command(CalloutHandle& handle) {
try {
impl->maintenanceStartHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_MAINTENANCE_START_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-maintenance-cancel command handler implementation.
int maintenance_cancel_command(CalloutHandle& handle) {
try {
impl->maintenanceCancelHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_MAINTENANCE_CANCEL_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-reset command handler implementation.
int ha_reset_command(CalloutHandle& handle) {
try {
impl->haResetHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_RESET_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief ha-sync-complete-notify command handler implementation.
int sync_complete_notify_command(CalloutHandle& handle) {
try {
impl->syncCompleteNotifyHandler(handle);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_SYNC_COMPLETE_NOTIFY_HANDLER_FAILED)
.arg(ex.what());
}
return (0);
}
/// @brief This function is called when the library is loaded.
///
/// @param handle library handle
/// @return 0 when initialization is successful, 1 otherwise
int load(LibraryHandle& handle) {
ConstElementPtr config = handle.getParameter("high-availability");
if (!config) {
LOG_ERROR(ha_logger, HA_MISSING_CONFIGURATION);
return (1);
}
try {
// Make the hook library not loadable by d2 or ca.
uint16_t family = CfgMgr::instance().getFamily();
const std::string& proc_name = Daemon::getProcName();
if (family == AF_INET) {
if (proc_name != "kea-dhcp4") {
isc_throw(isc::Unexpected, "Bad process name: " << proc_name
<< ", expected kea-dhcp4");
}
} else {
if (proc_name != "kea-dhcp6") {
isc_throw(isc::Unexpected, "Bad process name: " << proc_name
<< ", expected kea-dhcp6");
}
}
impl = boost::make_shared<HAImpl>();
impl->configure(config);
handle.registerCommandCallout("ha-heartbeat", heartbeat_command);
handle.registerCommandCallout("ha-sync", sync_command);
handle.registerCommandCallout("ha-scopes", scopes_command);
handle.registerCommandCallout("ha-continue", continue_command);
handle.registerCommandCallout("ha-maintenance-notify", maintenance_notify_command);
handle.registerCommandCallout("ha-maintenance-start", maintenance_start_command);
handle.registerCommandCallout("ha-maintenance-cancel", maintenance_cancel_command);
handle.registerCommandCallout("ha-reset", ha_reset_command);
handle.registerCommandCallout("ha-sync-complete-notify", sync_complete_notify_command);
} catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_CONFIGURATION_FAILED)
.arg(ex.what());
return (CONTROL_RESULT_ERROR);
}
LOG_INFO(ha_logger, HA_INIT_OK);
return (0);
}
/// @brief This function is called when the library is unloaded.
///
/// @return 0 if deregistration was successful, 1 otherwise
int unload() {
if (impl) {
IOServiceMgr::instance().unregisterIOService(impl->getIOService());
impl.reset();
}
LOG_INFO(ha_logger, HA_DEINIT_OK);
return (0);
}
/// @brief This function is called to retrieve the multi-threading compatibility.
///
/// @return 1 which means compatible with multi-threading.
int multi_threading_compatible() {
return (1);
}
} // end extern "C"