Commit 9f8d7460 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[1555] Open active V6 sockets when configuration is changed.

parent 0a5d26df
......@@ -26,7 +26,6 @@
#include <dhcp4/spec_config.h>
#include <dhcp4/config_parser.h>
#include <exceptions/exceptions.h>
#include <boost/bind.hpp>
#include <util/buffer.h>
#include <cassert>
......
......@@ -20,6 +20,7 @@
#include <config/ccsession.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
......@@ -100,7 +101,27 @@ ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
}
// Configure the server.
return (configureDhcp6Server(*server_, merged_config));
ConstElementPtr answer = configureDhcp6Server(*server_, merged_config);
// Check that configuration was successful. If not, do not reopen sockets.
int rcode = 0;
parseAnswer(rcode, answer);
if (rcode != 0) {
return (answer);
}
// Configuration may change active interfaces. Therefore, we have to reopen
// sockets according to new configuration. This operation is not exception
// safe and we really don't want to emit exceptions to the callback caller.
// Instead, catch an exception and create appropriate answer.
try {
server_->openActiveSockets(server_->getPort());
} catch (const std::exception& ex) {
std::ostringstream err;
err << "failed to open sockets after server reconfiguration: " << ex.what();
answer = isc::config::createAnswer(1, err.str());
}
return (answer);
}
ConstElementPtr
......@@ -228,6 +249,24 @@ ControlledDhcpv6Srv::execDhcpv6ServerCommand(const std::string& command_id,
}
}
void
ControlledDhcpv6Srv::openActiveSockets(const uint16_t port) {
IfaceMgr::instance().closeSockets();
// Get the reference to the collection of interfaces. This reference should be
// valid as long as the program is run because IfaceMgr is a singleton.
// Therefore we can safely iterate over instances of all interfaces and modify
// their flags. Here we modify flags which indicate wheter socket should be
// open for a particular interface or not.
IfaceMgr::IfaceCollection ifaces = IfaceMgr::instance().getIfaces();
for (IfaceMgr::IfaceCollection::iterator iface = ifaces.begin();
iface != ifaces.end(); ++iface) {
iface->inactive_ = !CfgMgr::instance().isActiveIface(iface->getName());
}
// Let's reopen active sockets. openSockets6 will check internally whether
// sockets are marked active or inactive.
IfaceMgr::instance().openSockets6(port);
}
};
};
......@@ -128,6 +128,17 @@ protected:
/// when there is a new command or configuration sent over msgq.
static void sessionReader(void);
/// @brief Open sockets which are marked as active in @c CfgMgr.
///
/// This function reopens sockets according to the current settings in the
/// Configuration Manager. It holds the list of the interfaces which server
/// should listen on. This function will open sockets on these interfaces
/// only. This function is not exception safe.
///
/// @param port UDP port on which server should listen.
/// @param use_bcast should broadcast flags be set on the sockets.
static void openActiveSockets(const uint16_t port);
/// @brief IOService object, used for all ASIO operations.
isc::asiolink::IOService io_service_;
......
......@@ -67,7 +67,7 @@ namespace dhcp {
static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
: alloc_engine_(), serverid_(), shutdown_(true) {
: alloc_engine_(), serverid_(), shutdown_(true), port_(port) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
......@@ -82,7 +82,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
return;
}
IfaceMgr::instance().openSockets6(port);
IfaceMgr::instance().openSockets6(port_);
}
string duid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_DUID_FILE);
......
......@@ -87,6 +87,19 @@ public:
/// @brief Instructs the server to shut down.
void shutdown();
/// @brief Get UDP port on which server should listen.
///
/// This accessor must be public because sockets are reopened from the
/// static configuration callback handler. This callback handler invokes
/// @c ControlledDhcpv4Srv::openActiveSockets which requires port parameter
/// which has to be retrieved from the @c ControlledDhcpv4Srv object.
/// They are retrieved using this public function.
///
/// @return UDP port on which server should listen.
uint16_t getPort() const {
return (port_);
}
protected:
/// @brief verifies if specified packet meets RFC requirements
......@@ -334,6 +347,8 @@ private:
/// Indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown_;
uint16_t port_; ///< UDP port number on which server listens.
};
}; // namespace isc::dhcp
......
......@@ -364,7 +364,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
if (iface->flag_loopback_ ||
!iface->flag_up_ ||
!iface->flag_running_,
!iface->inactive_) {
iface->inactive_) {
continue;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment