Commit d330a583 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[master] Merge branch 'master' of ssh://git.kea.isc.org/git/kea

Conflicts:
	ChangeLog
parents cc2e6681 ce6e519c
832. [bug] jiri
833. [bug] jiri
Compilation fix for PostgreSQL on i686. Thanks to Jiri Popelka
from RedHat for providing a patch!
(Trac #3532, git 96a06654f2177444dcea3a0e9f6fa06947855497)
832. [func] marcin
DHCP servers check if the interfaces specified in the configuration,
to be used to receive DHCP messsages, are present in the system.
If the interface doesn't exist, an error is reported. In addition,
the SO_REUSEPORT flag is set for IPv6 sockets as multiple multicast
sockets can be bound to the DHCPv6 server port.
(Trac #3512, git 5cbbab2d01c6e1bf6d563ba64d80bc6bc857f73d)
831. [bug] marcin
Kea deamons report configuration summary when the configuration is
completed successfully.
......
......@@ -177,7 +177,8 @@ void ControlledDhcpv4Srv::init(const std::string& config_file) {
// Configuration may disable or enable interfaces so we have to
// reopen sockets according to new configuration.
openActiveSockets(getPort(), useBroadcast());
CfgMgr::instance().getConfiguration()->cfg_iface_
.openSockets(getPort(), useBroadcast());
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
......
......@@ -18,6 +18,7 @@
#include <dhcp4/dhcp4_log.h>
#include <hooks/hooks_manager.h>
#include <dhcp4/json_config_parser.h>
#include <dhcpsrv/cfgmgr.h>
using namespace isc::data;
using namespace isc::hooks;
......@@ -117,7 +118,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
err << "Server object not initialized, can't process config.";
return (isc::config::createAnswer(1, err.str()));
}
ConstElementPtr answer = configureDhcp4Server(*srv, config);
......@@ -148,7 +149,9 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
// safe and we really don't want to emit exceptions to whoever called this
// method. Instead, catch an exception and create appropriate answer.
try {
srv->openActiveSockets(srv->getPort(), getInstance()->useBroadcast());
CfgMgr::instance().getConfiguration()->cfg_iface_
.openSockets(srv->getPort(), getInstance()->useBroadcast());
} catch (std::exception& ex) {
err << "failed to open sockets after server reconfiguration: "
<< ex.what();
......
......@@ -50,10 +50,11 @@ new configuration. It is output during server startup, and when an updated
configuration is committed by the administrator. Additional information
may be provided.
% DHCP4_CONFIG_LOAD_FAIL failed to load configuration: %1
This critical error message indicates that the initial DHCPv4
configuration has failed. The server will start, but nothing will be
served until the configuration has been corrected.
% DHCP4_CONFIG_LOAD_FAIL configuration error using file: %1, reason: %2
This error message indicates that the DHCPv4 configuration has failed.
If this is an initial configuration (during server's startup) the server
will fail to start. If this is a dynamic reconfiguration attempt the
server will continue to use an old configuration.
% DHCP4_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1
This is an informational message reporting that the configuration has
......
......@@ -1795,55 +1795,6 @@ Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
}
}
void
Dhcpv4Srv::openActiveSockets(const uint16_t port,
const bool use_bcast) {
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 whether socket
// should be open for a particular interface or not.
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
iface != ifaces.end(); ++iface) {
Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName());
if (iface_ptr == NULL) {
isc_throw(isc::Unexpected, "Interface Manager returned NULL"
<< " instance of the interface when DHCPv4 server was"
<< " trying to reopen sockets after reconfiguration");
}
// Ignore loopback interfaces.
if (iface_ptr->flag_loopback_) {
iface_ptr->inactive4_ = true;
} else if (CfgMgr::instance().isActiveIface(iface->getName())) {
iface_ptr->inactive4_ = false;
LOG_INFO(dhcp4_logger, DHCP4_ACTIVATE_INTERFACE)
.arg(iface->getFullName());
} else {
// For deactivating interface, it should be sufficient to log it
// on the debug level because it is more useful to know what
// interface is activated which is logged on the info level.
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
DHCP4_DEACTIVATE_INTERFACE).arg(iface->getName());
iface_ptr->inactive4_ = true;
}
}
// Let's reopen active sockets. openSockets4 will check internally whether
// sockets are marked active or inactive.
/// @todo Optimization: we should not reopen all sockets but rather select
/// those that have been affected by the new configuration.
isc::dhcp::IfaceMgrErrorMsgCallback error_handler =
boost::bind(&Dhcpv4Srv::ifaceMgrSocket4ErrorHandler, _1);
if (!IfaceMgr::instance().openSockets4(port, use_bcast, error_handler)) {
LOG_WARN(dhcp4_logger, DHCP4_NO_SOCKETS_OPEN);
}
}
size_t
Dhcpv4Srv::unpackOptions(const OptionBuffer& buf,
const std::string& option_space,
......
......@@ -128,11 +128,6 @@ public:
///
/// @name Public accessors returning values required to (re)open sockets.
///
/// These accessors must be public because sockets are reopened from the
/// static configuration callback handler. This callback handler invokes
/// @c ControlledDhcpv4Srv::openActiveSockets which requires parameters
/// which has to be retrieved from the @c ControlledDhcpv4Srv object.
/// They are retrieved using these public functions
//@{
///
/// @brief Get UDP port on which server should listen.
......@@ -154,17 +149,6 @@ public:
}
//@}
/// @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, const bool use_bcast);
/// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
///
/// If updates are enabled, it Instructs the D2ClientMgr singleton to
......
......@@ -594,8 +594,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
} catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
.arg(config_pair.first).arg(ex.what());
answer = isc::config::createAnswer(1,
string("Configuration parsing failed: ") + ex.what());
answer = isc::config::createAnswer(1, ex.what());
// An error occured, so make sure that we restore original data.
rollback = true;
......@@ -603,8 +602,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
} catch (...) {
// For things like bad_cast in boost::lexical_cast
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(config_pair.first);
answer = isc::config::createAnswer(1,
string("Configuration parsing failed"));
answer = isc::config::createAnswer(1, "undefined configuration"
" processing error");
// An error occured, so make sure that we restore original data.
rollback = true;
......@@ -636,14 +635,13 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
}
catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
answer = isc::config::createAnswer(2,
string("Configuration commit failed: ") + ex.what());
answer = isc::config::createAnswer(2, ex.what());
rollback = true;
} catch (...) {
// For things like bad_cast in boost::lexical_cast
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
answer = isc::config::createAnswer(2,
string("Configuration commit failed"));
answer = isc::config::createAnswer(2, "undefined configuration"
" parsing error");
rollback = true;
}
}
......@@ -659,7 +657,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
getConfigSummary(Configuration::CFGSEL_ALL4));
// Everything was fine. Configuration is successful.
answer = isc::config::createAnswer(0, "Configuration committed.");
answer = isc::config::createAnswer(0, "Configuration successful.");
return (answer);
}
......
......@@ -56,12 +56,8 @@ void configure(const std::string& file_name) {
// Read contents of the file and parse it as JSON
json = isc::data::Element::fromJSONFile(file_name, true);
if (!json) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Config file " + file_name + " missing or empty.");
isc_throw(isc::BadValue, "Unable to process JSON configuration"
" file: " << file_name);
isc_throw(isc::BadValue, "no configuration found");
}
// Let's configure logging before applying the configuration,
......@@ -75,46 +71,37 @@ void configure(const std::string& file_name) {
// Get Dhcp4 component from the config
dhcp4 = json->get("Dhcp4");
if (!dhcp4) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Config file " + file_name + " does not include 'Dhcp4'"
" entry.");
isc_throw(isc::BadValue, "Unable to process JSON configuration"
" file: " << file_name);
isc_throw(isc::BadValue, "no mandatory 'Dhcp4' entry in"
" the configuration");
}
// Use parsed JSON structures to configure the server
result = ControlledDhcpv4Srv::processCommand("config-reload", dhcp4);
if (!result) {
// Undetermined status of the configuration. This should never
// happen, but as the configureDhcp4Server returns a pointer, it is
// theoretically possible that it will return NULL.
isc_throw(isc::BadValue, "undefined result of "
"processCommand(\"config-reload\", dhcp4)");
}
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
isc_throw(isc::BadValue, "Unable to process JSON configuration file: "
<< file_name);
}
// Now check is the returned result is successful (rcode=0) or not
// (see @ref isc::config::parseAnswer).
int rcode;
isc::data::ConstElementPtr comment =
isc::config::parseAnswer(rcode, result);
if (rcode != 0) {
string reason = comment ? comment->stringValue() :
"no details available";
isc_throw(isc::BadValue, reason);
}
if (!result) {
// Undetermined status of the configuration. This should never happen,
// but as the configureDhcp4Server returns a pointer, it is
// theoretically possible that it will return NULL.
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Configuration failed: Undefined result of processCommand("
"config-reload, " + file_name + ")");
isc_throw(isc::BadValue, "Configuration failed: Undefined result of "
"processCommand('config-reload', " << file_name << ")");
}
// Now check is the returned result is successful (rcode=0) or not
isc::data::ConstElementPtr comment; /// see @ref isc::config::parseAnswer
int rcode;
comment = isc::config::parseAnswer(rcode, result);
if (rcode != 0) {
string reason = "";
if (comment) {
reason = comment->stringValue();
}
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(reason);
isc_throw(isc::BadValue, "Failed to apply configuration: " << reason);
.arg(file_name).arg(ex.what());
isc_throw(isc::BadValue, "configuration error using file '"
<< file_name << "': " << ex.what());
}
}
......
......@@ -25,6 +25,7 @@
#include <dhcp/option_int.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp/classify.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/testutils/config_result_check.h>
......@@ -77,7 +78,6 @@ public:
// deal with sockets here, just check if configuration handling
// is sane.
srv_.reset(new Dhcpv4Srv(0));
CfgMgr::instance().deleteActiveIfaces();
// Create fresh context.
globalContext()->copyContext(ParserContext(Option::V4));
}
......@@ -2895,6 +2895,8 @@ TEST_F(Dhcp4ParserTest, LibrariesSpecified) {
// This test verifies that it is possible to select subset of interfaces
// on which server should listen.
TEST_F(Dhcp4ParserTest, selectedInterfaces) {
IfaceMgrTestConfig test_config(true);
ConstElementPtr x;
string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
"\"rebind-timer\": 2000, "
......@@ -2907,24 +2909,26 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) {
// Make sure the config manager is clean and there is no hanging
// interface configuration.
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
EXPECT_FALSE(test_config.socketOpen("eth0", AF_INET));
EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));
// Apply configuration.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000);
// eth0 and eth1 were explicitly selected. eth2 was not.
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
EXPECT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
}
// This test verifies that it is possible to configure the server in such a way
// that it listens on all interfaces.
TEST_F(Dhcp4ParserTest, allInterfaces) {
IfaceMgrTestConfig test_config(true);
ConstElementPtr x;
// This configuration specifies two interfaces on which server should listen
// but it also includes asterisk. The asterisk switches server into the
......@@ -2940,19 +2944,19 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
ConstElementPtr status;
// Make sure there is no old configuration.
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
ASSERT_FALSE(test_config.socketOpen("eth0", AF_INET));
ASSERT_FALSE(test_config.socketOpen("eth1", AF_INET));
// Apply configuration.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000);
// All interfaces should be now active.
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
ASSERT_TRUE(test_config.socketOpen("eth0", AF_INET));
ASSERT_TRUE(test_config.socketOpen("eth1", AF_INET));
}
// This test checks the ability of the server to parse a configuration
......
......@@ -420,26 +420,6 @@ TEST_F(Dhcpv4SrvTest, basic) {
ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
}
// This test verifies that exception is not thrown when an error occurs during
// opening sockets. This test forces an error by adding a fictious interface
// to the IfaceMgr. An attempt to open socket on this interface must always
// fail. The DHCPv4 installs the error handler function to prevent exceptions
// being thrown from the openSockets4 function.
// @todo The server tests for socket should be extended but currently the
// ability to unit test the sockets code is somewhat limited.
TEST_F(Dhcpv4SrvTest, openActiveSockets) {
ASSERT_NO_THROW(CfgMgr::instance().activateAllIfaces());
Iface iface("bogusiface", 255);
iface.flag_loopback_ = false;
iface.flag_up_ = true;
iface.flag_running_ = true;
iface.inactive4_ = false;
iface.addAddress(IOAddress("192.0.0.0"));
IfaceMgr::instance().addInterface(iface);
ASSERT_NO_THROW(Dhcpv4Srv::openActiveSockets(DHCP4_SERVER_PORT, false));
}
// Verifies that DISCOVER message can be processed correctly,
// that the OFFER message generated in response is valid and
// contains necessary options.
......@@ -2970,7 +2950,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
NakedDhcpv4Srv srv(0);
ConstElementPtr x;
string config = "{ \"interfaces\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
" \"option-data\": [ {"
......@@ -3055,7 +3035,7 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
ConstElementPtr x;
string config_prefix = "{ \"interfaces\": [ \"all\" ],"
string config_prefix = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
" \"option-data\": [ {"
......
......@@ -45,7 +45,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
subnet_->addPool(pool_);
CfgMgr::instance().deleteActiveIfaces();
CfgMgr::instance().getConfiguration()->cfg_iface_.reset();
CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().addSubnet4(subnet_);
......@@ -58,6 +58,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
Dhcpv4SrvTest::~Dhcpv4SrvTest() {
// Make sure that we revert to default value
CfgMgr::instance().getConfiguration()->cfg_iface_.reset();
CfgMgr::instance().echoClientId(true);
}
......
......@@ -49,7 +49,7 @@ namespace {
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
const char* DORA_CONFIGS[] = {
// Configuration 0
"{ \"interfaces\": [ \"all\" ],"
"{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", "
......@@ -86,7 +86,7 @@ const char* DORA_CONFIGS[] = {
"}",
// Configuration 1
"{ \"interfaces\": [ \"all\" ],"
"{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", "
......
......@@ -48,7 +48,7 @@ namespace {
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
const char* INFORM_CONFIGS[] = {
// Configuration 0
"{ \"interfaces\": [ \"all\" ],"
"{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"10.0.0.0/24\", "
......@@ -85,7 +85,7 @@ const char* INFORM_CONFIGS[] = {
"}",
// Configuration 1
"{ \"interfaces\": [ \"all\" ],"
"{ \"interfaces\": [ \"*\" ],"
"\"valid-lifetime\": 600,"
"\"subnet4\": [ { "
" \"subnet\": \"192.0.2.0/24\", "
......
......@@ -183,7 +183,10 @@ ControlledDhcpv6Srv::init(const std::string& config_file) {
// Configuration may disable or enable interfaces so we have to
// reopen sockets according to new configuration.
openActiveSockets(getPort());
// Configuration may disable or enable interfaces so we have to
// reopen sockets according to new configuration.
CfgMgr::instance().getConfiguration()->cfg_iface_
.openSockets(getPort(), useBroadcast());
} catch (const std::exception& ex) {
LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL).arg(ex.what());
......
......@@ -14,6 +14,7 @@
#include <config.h>
#include <cc/data.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <hooks/hooks_manager.h>
......@@ -143,10 +144,13 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
// safe and we really don't want to emit exceptions to the callback caller.
// Instead, catch an exception and create appropriate answer.
try {
srv->openActiveSockets(srv->getPort());
CfgMgr::instance().getConfiguration()->cfg_iface_
.openSockets(srv->getPort());
} catch (const std::exception& ex) {
std::ostringstream err;
err << "failed to open sockets after server reconfiguration: " << ex.what();
err << "failed to open sockets after server reconfiguration: "
<< ex.what();
answer = isc::config::createAnswer(1, err.str());
}
......
......@@ -46,10 +46,11 @@ new configuration. it is output during server startup, and when an updated
configuration is committed by the administrator. Additional information
may be provided.
% DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
This critical error message indicates that the initial DHCPv6
configuration has failed. The server will start, but nothing will be
served until the configuration has been corrected.
% DHCP6_CONFIG_LOAD_FAIL configuration error using file: %1, reason: %2
This error message indicates that the DHCPv6 configuration has failed.
If this is an initial configuration (during server's startup) the server
will fail to start. If this is a dynamic reconfiguration attempt the
server will continue to use an old configuration.
% DHCP6_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1
This is an informational message reporting that the configuration has
......
......@@ -150,6 +150,12 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
// Instantiate allocation engine
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
// We have to point out to the CfgMgr that the we are in the IPv6
// domain, so as the IPv6 sockets are opened rather than IPv4 sockets
// which are the default.
CfgMgr::instance().getConfiguration()
->cfg_iface_.setFamily(CfgIface::V6);
/// @todo call loadLibraries() when handling configuration changes
} catch (const std::exception &e) {
......@@ -2429,64 +2435,6 @@ Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
return reply;
}
void
Dhcpv6Srv::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.
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
iface != ifaces.end(); ++iface) {
Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName());
if (iface_ptr == NULL) {
isc_throw(isc::Unexpected, "Interface Manager returned NULL"
<< " instance of the interface when DHCPv6 server was"
<< " trying to reopen sockets after reconfiguration");
}
// Ignore loopback interfaces.
if (iface_ptr->flag_loopback_) {
iface_ptr->inactive6_ = true;
} else if (CfgMgr::instance().isActiveIface(iface->getName())) {
iface_ptr->inactive6_ = false;
LOG_INFO(dhcp6_logger, DHCP6_ACTIVATE_INTERFACE)
.arg(iface->getFullName());
} else {
// For deactivating interface, it should be sufficient to log it
// on the debug level because it is more useful to know what
// interface is activated which is logged on the info level.
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
DHCP6_DEACTIVATE_INTERFACE).arg(iface->getName());
iface_ptr->inactive6_ = true;
}
iface_ptr->clearUnicasts();
const IOAddress* unicast = CfgMgr::instance().getUnicast(iface->getName());
if (unicast) {
LOG_INFO(dhcp6_logger, DHCP6_SOCKET_UNICAST).arg(unicast->toText())
.arg(iface->getName());
iface_ptr->addUnicast(*unicast);
}
}
// Let's reopen active sockets. openSockets6 will check internally whether
// sockets are marked active or inactive.
// @todo Optimization: we should not reopen all sockets but rather select
// those that have been affected by the new configuration.
isc::dhcp::IfaceMgrErrorMsgCallback error_handler =
boost::bind(&Dhcpv6Srv::ifaceMgrSocket6ErrorHandler, _1);
if (!IfaceMgr::instance().openSockets6(port, error_handler)) {
LOG_WARN(dhcp6_logger, DHCP6_NO_SOCKETS_OPEN);
}
}
size_t
Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
const std::string& option_space,
......
......@@ -100,27 +100,11 @@ public:
/// Typically, server listens on UDP port 547. Other ports are only
/// used for testing purposes.
///
/// 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_);
}
/// @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.