Commit 59cd21bb authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[3534] Basic implementation of staging and rolling back configurations.

parent 135e6a45
...@@ -149,8 +149,9 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) { ...@@ -149,8 +149,9 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
// safe and we really don't want to emit exceptions to whoever called this // safe and we really don't want to emit exceptions to whoever called this
// method. Instead, catch an exception and create appropriate answer. // method. Instead, catch an exception and create appropriate answer.
try { try {
CfgMgr::instance().getConfiguration()->cfg_iface_ CfgMgr::instance().getCurrent()->getCfgIface()
.openSockets(srv->getPort(), getInstance()->useBroadcast()); .openSockets(CfgIface::V4, srv->getPort(),
getInstance()->useBroadcast());
} catch (std::exception& ex) { } catch (std::exception& ex) {
err << "failed to open sockets after server reconfiguration: " err << "failed to open sockets after server reconfiguration: "
......
...@@ -443,7 +443,7 @@ namespace dhcp { ...@@ -443,7 +443,7 @@ namespace dhcp {
parser = new Uint32Parser(config_id, parser = new Uint32Parser(config_id,
globalContext()->uint32_values_); globalContext()->uint32_values_);
} else if (config_id.compare("interfaces") == 0) { } else if (config_id.compare("interfaces") == 0) {
parser = new InterfaceListConfigParser(config_id); parser = new InterfaceListConfigParser(config_id, globalContext());
} else if (config_id.compare("subnet4") == 0) { } else if (config_id.compare("subnet4") == 0) {
parser = new Subnets4ListConfigParser(config_id); parser = new Subnets4ListConfigParser(config_id);
} else if (config_id.compare("option-data") == 0) { } else if (config_id.compare("option-data") == 0) {
...@@ -619,9 +619,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) { ...@@ -619,9 +619,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
subnet_parser->commit(); subnet_parser->commit();
} }
if (iface_parser) { // No need to commit interface names as this is handled by the
iface_parser->commit(); // CfgMgr::commit() function.
}
// Apply global options // Apply global options
commitGlobalOptions(); commitGlobalOptions();
...@@ -649,6 +648,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) { ...@@ -649,6 +648,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Rollback changes as the configuration parsing failed. // Rollback changes as the configuration parsing failed.
if (rollback) { if (rollback) {
globalContext().reset(new ParserContext(original_context)); globalContext().reset(new ParserContext(original_context));
CfgMgr::instance().rollback();
return (answer); return (answer);
} }
......
...@@ -41,6 +41,11 @@ void configure(const std::string& file_name) { ...@@ -41,6 +41,11 @@ void configure(const std::string& file_name) {
// This is a configuration backend implementation that reads the // This is a configuration backend implementation that reads the
// configuration from a JSON file. // configuration from a JSON file.
// We are starting the configuration process so we should remove any
// staging configuration that has been created during previous
// configuration attempts.
CfgMgr::instance().rollback();
isc::data::ConstElementPtr json; isc::data::ConstElementPtr json;
isc::data::ConstElementPtr dhcp4; isc::data::ConstElementPtr dhcp4;
isc::data::ConstElementPtr logger; isc::data::ConstElementPtr logger;
...@@ -66,7 +71,7 @@ void configure(const std::string& file_name) { ...@@ -66,7 +71,7 @@ void configure(const std::string& file_name) {
// If there's no logging element, we'll just pass NULL pointer, // If there's no logging element, we'll just pass NULL pointer,
// which will be handled by configureLogger(). // which will be handled by configureLogger().
Daemon::configureLogger(json->get("Logging"), Daemon::configureLogger(json->get("Logging"),
CfgMgr::instance().getConfiguration(), CfgMgr::instance().getStaging(),
ControlledDhcpv4Srv::getInstance()->getVerbose()); ControlledDhcpv4Srv::getInstance()->getVerbose());
// Get Dhcp4 component from the config // Get Dhcp4 component from the config
......
...@@ -2917,7 +2917,8 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) { ...@@ -2917,7 +2917,8 @@ TEST_F(Dhcp4ParserTest, selectedInterfaces) {
ASSERT_TRUE(status); ASSERT_TRUE(status);
checkResult(status, 0); checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000); CfgMgr::instance().getStaging()->
getCfgIface().openSockets(CfgIface::V4, 10000);
// eth0 and eth1 were explicitly selected. eth2 was not. // eth0 and eth1 were explicitly selected. eth2 was not.
EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET)); EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
...@@ -2952,7 +2953,8 @@ TEST_F(Dhcp4ParserTest, allInterfaces) { ...@@ -2952,7 +2953,8 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
ASSERT_TRUE(status); ASSERT_TRUE(status);
checkResult(status, 0); checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000); CfgMgr::instance().getStaging()->
getCfgIface().openSockets(CfgIface::V4, 10000);
// All interfaces should be now active. // All interfaces should be now active.
ASSERT_TRUE(test_config.socketOpen("eth0", AF_INET)); ASSERT_TRUE(test_config.socketOpen("eth0", AF_INET));
......
...@@ -45,7 +45,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest() ...@@ -45,7 +45,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110"))); pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
subnet_->addPool(pool_); subnet_->addPool(pool_);
CfgMgr::instance().getConfiguration()->cfg_iface_.reset(); CfgMgr::instance().clear();
CfgMgr::instance().deleteSubnets4(); CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().addSubnet4(subnet_); CfgMgr::instance().addSubnet4(subnet_);
...@@ -58,7 +58,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest() ...@@ -58,7 +58,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
Dhcpv4SrvTest::~Dhcpv4SrvTest() { Dhcpv4SrvTest::~Dhcpv4SrvTest() {
// Make sure that we revert to default value // Make sure that we revert to default value
CfgMgr::instance().getConfiguration()->cfg_iface_.reset(); CfgMgr::instance().clear();
CfgMgr::instance().echoClientId(true); CfgMgr::instance().echoClientId(true);
} }
......
...@@ -144,8 +144,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) { ...@@ -144,8 +144,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
// safe and we really don't want to emit exceptions to the callback caller. // safe and we really don't want to emit exceptions to the callback caller.
// Instead, catch an exception and create appropriate answer. // Instead, catch an exception and create appropriate answer.
try { try {
CfgMgr::instance().getConfiguration()->cfg_iface_ CfgMgr::instance().getConfiguration()->getCfgIface()
.openSockets(srv->getPort()); .openSockets(CfgIface::V6, srv->getPort());
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
std::ostringstream err; std::ostringstream err;
......
...@@ -150,12 +150,6 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) ...@@ -150,12 +150,6 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
// Instantiate allocation engine // Instantiate allocation engine
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)); 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 /// @todo call loadLibraries() when handling configuration changes
} catch (const std::exception &e) { } catch (const std::exception &e) {
......
...@@ -662,7 +662,7 @@ namespace dhcp { ...@@ -662,7 +662,7 @@ namespace dhcp {
parser = new Uint32Parser(config_id, parser = new Uint32Parser(config_id,
globalContext()->uint32_values_); globalContext()->uint32_values_);
} else if (config_id.compare("interfaces") == 0) { } else if (config_id.compare("interfaces") == 0) {
parser = new InterfaceListConfigParser(config_id); parser = new InterfaceListConfigParser(config_id, globalContext());
} else if (config_id.compare("subnet6") == 0) { } else if (config_id.compare("subnet6") == 0) {
parser = new Subnets6ListConfigParser(config_id); parser = new Subnets6ListConfigParser(config_id);
} else if (config_id.compare("option-data") == 0) { } else if (config_id.compare("option-data") == 0) {
...@@ -821,9 +821,8 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) { ...@@ -821,9 +821,8 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
subnet_parser->commit(); subnet_parser->commit();
} }
if (iface_parser) { // No need to commit interface names as this is handled by the
iface_parser->commit(); // CfgMgr::commit() function.
}
// This occurs last as if it succeeds, there is no easy way to // This occurs last as if it succeeds, there is no easy way to
// revert it. As a result, the failure to commit a subsequent // revert it. As a result, the failure to commit a subsequent
...@@ -850,6 +849,7 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) { ...@@ -850,6 +849,7 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
// Rollback changes as the configuration parsing failed. // Rollback changes as the configuration parsing failed.
if (rollback) { if (rollback) {
globalContext().reset(new ParserContext(original_context)); globalContext().reset(new ParserContext(original_context));
CfgMgr::instance().rollback();
return (answer); return (answer);
} }
......
...@@ -45,6 +45,11 @@ void configure(const std::string& file_name) { ...@@ -45,6 +45,11 @@ void configure(const std::string& file_name) {
// This is a configuration backend implementation that reads the // This is a configuration backend implementation that reads the
// configuration from a JSON file. // configuration from a JSON file.
// We are starting the configuration process so we should remove any
// staging configuration that has been created during previous
// configuration attempts.
CfgMgr::instance().rollback();
isc::data::ConstElementPtr json; isc::data::ConstElementPtr json;
isc::data::ConstElementPtr dhcp6; isc::data::ConstElementPtr dhcp6;
isc::data::ConstElementPtr logger; isc::data::ConstElementPtr logger;
......
...@@ -359,9 +359,7 @@ public: ...@@ -359,9 +359,7 @@ public:
// properly test interface configuration we disable listening on // properly test interface configuration we disable listening on
// all interfaces before each test and later check that this setting // all interfaces before each test and later check that this setting
// has been overriden by the configuration used in the test. // has been overriden by the configuration used in the test.
CfgMgr::instance().getConfiguration()->cfg_iface_.reset(); CfgMgr::instance().clear();
CfgMgr::instance().getConfiguration()->
cfg_iface_.setFamily(CfgIface::V6);
// Create fresh context. // Create fresh context.
globalContext()->copyContext(ParserContext(Option::V6)); globalContext()->copyContext(ParserContext(Option::V6));
} }
...@@ -3057,7 +3055,8 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) { ...@@ -3057,7 +3055,8 @@ TEST_F(Dhcp6ParserTest, selectedInterfaces) {
// as the pool does not belong to that subnet // as the pool does not belong to that subnet
checkResult(status, 0); checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000); CfgMgr::instance().getStaging()->
getCfgIface().openSockets(CfgIface::V6, 10000);
// eth0 and eth1 were explicitly selected. eth2 was not. // eth0 and eth1 were explicitly selected. eth2 was not.
EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6)); EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6));
...@@ -3075,7 +3074,7 @@ TEST_F(Dhcp6ParserTest, allInterfaces) { ...@@ -3075,7 +3074,7 @@ TEST_F(Dhcp6ParserTest, allInterfaces) {
ConstElementPtr status; ConstElementPtr status;
// This configuration specifies two interfaces on which server should listen // This configuration specifies two interfaces on which server should listen
// bu also includes keyword 'all'. This keyword switches server into the // but also includes '*'. This keyword switches server into the
// mode when it listens on all interfaces regardless of what interface names // mode when it listens on all interfaces regardless of what interface names
// were specified in the "interfaces" parameter. // were specified in the "interfaces" parameter.
string config = "{ \"interfaces\": [ \"eth0\", \"eth1\", \"*\" ]," string config = "{ \"interfaces\": [ \"eth0\", \"eth1\", \"*\" ],"
...@@ -3090,7 +3089,8 @@ TEST_F(Dhcp6ParserTest, allInterfaces) { ...@@ -3090,7 +3089,8 @@ TEST_F(Dhcp6ParserTest, allInterfaces) {
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
checkResult(status, 0); checkResult(status, 0);
CfgMgr::instance().getConfiguration()->cfg_iface_.openSockets(10000); CfgMgr::instance().getStaging()->
getCfgIface().openSockets(CfgIface::V6, 10000);
// All interfaces should be now active. // All interfaces should be now active.
EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6)); EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET6));
......
...@@ -25,24 +25,24 @@ namespace dhcp { ...@@ -25,24 +25,24 @@ namespace dhcp {
const char* CfgIface::ALL_IFACES_KEYWORD = "*"; const char* CfgIface::ALL_IFACES_KEYWORD = "*";
CfgIface::CfgIface(Family family) CfgIface::CfgIface()
: family_(family), : wildcard_used_(false) {
wildcard_used_(false) {
} }
void void
CfgIface::closeSockets() { CfgIface::closeSockets() const {
IfaceMgr::instance().closeSockets(); IfaceMgr::instance().closeSockets();
} }
void void
CfgIface::openSockets(const uint16_t port, const bool use_bcast) { CfgIface::openSockets(const Family& family, const uint16_t port,
const bool use_bcast) const {
// If wildcard interface '*' was not specified, set all interfaces to // If wildcard interface '*' was not specified, set all interfaces to
// inactive state. We will later enable them selectively using the // inactive state. We will later enable them selectively using the
// interface names specified by the user. If wildcard interface was // interface names specified by the user. If wildcard interface was
// specified, mark all interfaces active. In all cases, mark loopback // specified, mark all interfaces active. In all cases, mark loopback
// inactive. // inactive.
setState(!wildcard_used_, true); setState(family, !wildcard_used_, true);
// Remove selection of unicast addresses from all interfaces. // Remove selection of unicast addresses from all interfaces.
IfaceMgr::instance().clearUnicasts(); IfaceMgr::instance().clearUnicasts();
// If there is no wildcard interface specified, we will have to iterate // If there is no wildcard interface specified, we will have to iterate
...@@ -61,7 +61,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) { ...@@ -61,7 +61,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) {
<< *iface_name << "' as this interface doesn't" << *iface_name << "' as this interface doesn't"
" exist"); " exist");
} else if (getFamily() == V4) { } else if (family == V4) {
iface->inactive4_ = false; iface->inactive4_ = false;
} else { } else {
...@@ -71,7 +71,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) { ...@@ -71,7 +71,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) {
} }
// Select unicast sockets. It works only for V6. Ignore for V4. // Select unicast sockets. It works only for V6. Ignore for V4.
if (getFamily() == V6) { if (family == V6) {
for (UnicastMap::const_iterator unicast = unicast_map_.begin(); for (UnicastMap::const_iterator unicast = unicast_map_.begin();
unicast != unicast_map_.end(); ++unicast) { unicast != unicast_map_.end(); ++unicast) {
Iface* iface = IfaceMgr::instance().getIface(unicast->first); Iface* iface = IfaceMgr::instance().getIface(unicast->first);
...@@ -95,7 +95,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) { ...@@ -95,7 +95,7 @@ CfgIface::openSockets(const uint16_t port, const bool use_bcast) {
IfaceMgrErrorMsgCallback error_callback = IfaceMgrErrorMsgCallback error_callback =
boost::bind(&CfgIface::socketOpenErrorHandler, _1); boost::bind(&CfgIface::socketOpenErrorHandler, _1);
bool sopen; bool sopen;
if (getFamily() == V4) { if (family == V4) {
sopen = IfaceMgr::instance().openSockets4(port, use_bcast, sopen = IfaceMgr::instance().openSockets4(port, use_bcast,
error_callback); error_callback);
} else { } else {
...@@ -117,12 +117,13 @@ CfgIface::reset() { ...@@ -117,12 +117,13 @@ CfgIface::reset() {
} }
void void
CfgIface::setState(const bool inactive, const bool loopback_inactive) { CfgIface::setState(const Family& family, const bool inactive,
const bool loopback_inactive) const {
IfaceMgr::IfaceCollection ifaces = IfaceMgr::instance().getIfaces(); IfaceMgr::IfaceCollection ifaces = IfaceMgr::instance().getIfaces();
for (IfaceMgr::IfaceCollection::iterator iface = ifaces.begin(); for (IfaceMgr::IfaceCollection::iterator iface = ifaces.begin();
iface != ifaces.end(); ++iface) { iface != ifaces.end(); ++iface) {
Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName()); Iface* iface_ptr = IfaceMgr::instance().getIface(iface->getName());
if (getFamily() == V4) { if (family == V4) {
iface_ptr->inactive4_ = iface_ptr->flag_loopback_ ? iface_ptr->inactive4_ = iface_ptr->flag_loopback_ ?
loopback_inactive : inactive; loopback_inactive : inactive;
} else { } else {
...@@ -138,7 +139,7 @@ CfgIface::socketOpenErrorHandler(const std::string& errmsg) { ...@@ -138,7 +139,7 @@ CfgIface::socketOpenErrorHandler(const std::string& errmsg) {
} }
void void
CfgIface::use(const std::string& iface_name) { CfgIface::use(const Family& family, const std::string& iface_name) {
// The interface name specified may have two formats, e.g.: // The interface name specified may have two formats, e.g.:
// - eth0 // - eth0
// - eth0/2001:db8:1::1. // - eth0/2001:db8:1::1.
...@@ -184,7 +185,7 @@ CfgIface::use(const std::string& iface_name) { ...@@ -184,7 +185,7 @@ CfgIface::use(const std::string& iface_name) {
} }
} else if (getFamily() == V4) { } else if (family == V4) {
isc_throw(InvalidIfaceName, "unicast addresses in the format of: " isc_throw(InvalidIfaceName, "unicast addresses in the format of: "
"iface-name/unicast-addr_stress can only be specified for" "iface-name/unicast-addr_stress can only be specified for"
" IPv6 addr_stress family"); " IPv6 addr_stress family");
......
...@@ -81,17 +81,10 @@ public: ...@@ -81,17 +81,10 @@ public:
}; };
/// @brief Constructor. /// @brief Constructor.
/// CfgIface();
/// @param family Protocol family (default is V4).
CfgIface(Family family = V4);
/// @brief Convenience function which closes all open sockets. /// @brief Convenience function which closes all open sockets.
void closeSockets(); void closeSockets() const;
/// @brief Returns protocol family used by the @c CfgIface.
Family getFamily() const {
return (family_);
}
/// @brief Tries to open sockets on selected interfaces. /// @brief Tries to open sockets on selected interfaces.
/// ///
...@@ -100,24 +93,19 @@ public: ...@@ -100,24 +93,19 @@ public:
/// documentation for details how to specify interfaces and unicast /// documentation for details how to specify interfaces and unicast
/// addresses to bind the sockets to. /// addresses to bind the sockets to.
/// ///
/// @param family Address family (v4 or v6).
/// @param port Port number to be used to bind sockets to. /// @param port Port number to be used to bind sockets to.
/// @param use_bcast A boolean flag which indicates if the broadcast /// @param use_bcast A boolean flag which indicates if the broadcast
/// traffic should be received through the socket. This parameter is /// traffic should be received through the socket. This parameter is
/// ignored for IPv6. /// ignored for IPv6.
void openSockets(const uint16_t port, const bool use_bcast = true); void openSockets(const Family& family, const uint16_t port,
const bool use_bcast = true) const;
/// @brief Puts the interface configuration into default state. /// @brief Puts the interface configuration into default state.
/// ///
/// This function removes interface names from the set. /// This function removes interface names from the set.
void reset(); void reset();
/// @brief Sets protocol family.
///
/// @param family New family value (V4 or V6).
void setFamily(Family family) {
family_ = family;
}
/// @brief Select interface to be used to receive DHCP traffic. /// @brief Select interface to be used to receive DHCP traffic.
/// ///
/// This function controls the selection of the interface on which the /// This function controls the selection of the interface on which the
...@@ -137,6 +125,7 @@ public: ...@@ -137,6 +125,7 @@ public:
/// not allowed when specifying a unicast address. For example: /// not allowed when specifying a unicast address. For example:
/// */2001:db8:1::1 is not allowed. /// */2001:db8:1::1 is not allowed.
/// ///
/// @param family Address family (v4 or v6).
/// @param iface_name Explicit interface name, a wildcard name (*) of /// @param iface_name Explicit interface name, a wildcard name (*) of
/// the interface(s) or the pair of iterface/unicast-address to be used /// the interface(s) or the pair of iterface/unicast-address to be used
/// to receive DHCP traffic. /// to receive DHCP traffic.
...@@ -148,7 +137,7 @@ public: ...@@ -148,7 +137,7 @@ public:
/// @throw DuplicateIfaceName If the interface is already selected, i.e. /// @throw DuplicateIfaceName If the interface is already selected, i.e.
/// @throw IOError when specified unicast address is invalid. /// @throw IOError when specified unicast address is invalid.
/// @c CfgIface::use has been already called for this interface. /// @c CfgIface::use has been already called for this interface.
void use(const std::string& iface_name); void use(const Family& family, const std::string& iface_name);
private: private:
...@@ -157,12 +146,14 @@ private: ...@@ -157,12 +146,14 @@ private:
/// This function selects all interfaces to receive DHCP traffic or /// This function selects all interfaces to receive DHCP traffic or
/// deselects all interfaces so as none of them receives a DHCP traffic. /// deselects all interfaces so as none of them receives a DHCP traffic.
/// ///
/// @param family Address family (v4 or v6).
/// @param inactive A boolean value which indicates if all interfaces /// @param inactive A boolean value which indicates if all interfaces
/// (except loopback) should be selected or deselected. /// (except loopback) should be selected or deselected.
/// @param loopback_inactive A boolean value which indicates if loopback /// @param loopback_inactive A boolean value which indicates if loopback
/// interface should be selected or deselected. /// interface should be selected or deselected.
/// should be deselected/inactive (true) or selected/active (false). /// should be deselected/inactive (true) or selected/active (false).
void setState(const bool inactive, const bool loopback_inactive); void setState(const Family& family, const bool inactive,
const bool loopback_inactive) const;
/// @brief Error handler for executed when opening a socket fail. /// @brief Error handler for executed when opening a socket fail.
/// ///
......
...@@ -357,17 +357,63 @@ CfgMgr::getD2ClientMgr() { ...@@ -357,17 +357,63 @@ CfgMgr::getD2ClientMgr() {
return (d2_client_mgr_); return (d2_client_mgr_);
} }
void
CfgMgr::ensureCurrentAllocated() {
if (!configuration_ || configs_.empty()) {
configuration_.reset(new Configuration());
configs_.push_back(configuration_);
}
}
void
CfgMgr::clear() {
configs_.clear();
ensureCurrentAllocated();
}
void
CfgMgr::commit() {
if (!configs_.empty() && configs_.back() != configuration_) {
configuration_ = configs_.back();
}
}
void
CfgMgr::rollback() {
ensureCurrentAllocated();
if (!configuration_->sequenceEquals(*configs_.back())) {
configs_.pop_back();
}
}
ConfigurationPtr ConfigurationPtr
CfgMgr::getConfiguration() { CfgMgr::getConfiguration() {
return (configuration_); return (configuration_);
} }
ConstConfigurationPtr
CfgMgr::getCurrent() {
ensureCurrentAllocated();
return (configuration_);
}
ConfigurationPtr
CfgMgr::getStaging() {
ensureCurrentAllocated();