From: Marcin Siodelski Date: Mon, 4 Dec 2017 14:04:47 +0000 (+0100) Subject: [5442] Implemented 'dhcp-disable' and 'dhcp-enable' commands for DHCPv6. X-Git-Tag: trac5443_base~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc7e9a669f4f5e4a1676d44a9f2c58403e714c63;p=thirdparty%2Fkea.git [5442] Implemented 'dhcp-disable' and 'dhcp-enable' commands for DHCPv6. --- diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 87bf60bfde..eeadd5e70d 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -20,6 +20,7 @@ #include #include #include +#include using namespace isc::config; using namespace isc::dhcp; @@ -377,6 +378,64 @@ ControlledDhcpv6Srv::commandConfigTestHandler(const string&, return (checkConfig(dhcp6)); } +ConstElementPtr +ControlledDhcpv6Srv::commandDhcpDisableHandler(const std::string&, + ConstElementPtr args) { + std::ostringstream message; + int64_t max_period = 0; + + // Parse arguments to see if the 'max-period' parameter has been specified. + if (args) { + // Arguments must be a map. + if (args->getType() != Element::map) { + message << "arguments for the 'dhcp-disable' command must be a map"; + + } else { + ConstElementPtr max_period_element = args->get("max-period"); + // max-period is optional. + if (max_period_element) { + // It must be an integer, if specified. + if (max_period_element->getType() != Element::integer) { + message << "'max-period' argument must be a number"; + + } else { + // It must be positive integer. + max_period = max_period_element->intValue(); + if (max_period <= 0) { + message << "'max-period' must be positive integer"; + } + + // The user specified that the DHCP service should resume not + // later than in max-period seconds. If the 'dhcp-enable' command + // is not sent, the DHCP service will resume automatically. + network_state_.delayedEnableAll(static_cast(max_period)); + } + } + } + } + + // No error occurred, so let's disable the service. + if (message.tellp() == 0) { + network_state_.disableService(); + + message << "DHCPv4 service disabled"; + if (max_period > 0) { + message << " for " << max_period << " seconds"; + } + // Success. + return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str())); + } + + // Failure. + return (config::createAnswer(CONTROL_RESULT_ERROR, message.str())); +} + +ConstElementPtr +ControlledDhcpv6Srv::commandDhcpEnableHandler(const std::string&, ConstElementPtr) { + network_state_.enableService(); + return (config::createAnswer(CONTROL_RESULT_SUCCESS, "DHCP service successfully enabled")); +} + ConstElementPtr ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) { ElementPtr extended = Element::create(Dhcpv6Srv::getVersion(true)); @@ -457,6 +516,12 @@ ControlledDhcpv6Srv::processCommand(const std::string& command, } else if (command == "config-test") { return (srv->commandConfigTestHandler(command, args)); + } else if (command == "dhcp-disable") { + return (srv->commandDhcpDisableHandler(command, args)); + + } else if (command == "dhcp-enable") { + return (srv->commandDhcpEnableHandler(command, args)); + } else if (command == "version-get") { return (srv->commandVersionGetHandler(command, args)); @@ -638,6 +703,12 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port) CommandMgr::instance().registerCommand("config-write", boost::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("dhcp-disable", + boost::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, _1, _2)); + + CommandMgr::instance().registerCommand("dhcp-enable", + boost::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("leases-reclaim", boost::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, _1, _2)); @@ -694,6 +765,8 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() { CommandMgr::instance().deregisterCommand("config-reload"); CommandMgr::instance().deregisterCommand("config-test"); CommandMgr::instance().deregisterCommand("config-write"); + CommandMgr::instance().deregisterCommand("dhcp-disable"); + CommandMgr::instance().deregisterCommand("dhcp-enable"); CommandMgr::instance().deregisterCommand("leases-reclaim"); CommandMgr::instance().deregisterCommand("libreload"); CommandMgr::instance().deregisterCommand("shutdown"); diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h index 4648aefb5c..21d7e7493d 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.h +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h @@ -223,6 +223,27 @@ private: commandConfigTestHandler(const std::string& command, isc::data::ConstElementPtr args); + /// @brief A handler for processing 'dhcp-disable' command. + /// + /// @param command command name (ignored). + /// @param args aguments for the command. It must be a map and + /// it may include optional 'max-period' parameter. + /// + /// @return result of the command. + isc::data::ConstElementPtr + commandDhcpDisableHandler(const std::string& command, + isc::data::ConstElementPtr args); + + /// @brief A handler for processing 'dhcp-enable' command. + /// + /// @param command command name (ignored) + /// @param args arguments for the command (ignored). + /// + /// @return result of the command. + isc::data::ConstElementPtr + commandDhcpEnableHandler(const std::string& command, + isc::data::ConstElementPtr args); + /// @Brief handler for processing 'version-get' command /// /// This handler processes version-get command, which returns diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index 9e24fdb249..b105e5557d 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -83,6 +83,7 @@ public: /// Expose internal methods for the sake of testing using Dhcpv6Srv::receivePacket; + using Dhcpv6Srv::network_state_; }; /// @brief Default control connection timeout. @@ -1175,6 +1176,74 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configReloadValid) { ::remove("test8.json"); } +// This test verifies if it is possible to disable DHCP service via command. +TEST_F(CtrlChannelDhcpv6SrvTest, dhcpDisable) { + createUnixChannelServer(); + std::string response; + + sendUnixCommand("{ \"command\": \"dhcp-disable\" }", response); + ConstElementPtr rsp; + + // The response should be a valid JSON. + EXPECT_NO_THROW(rsp = Element::fromJSON(response)); + ASSERT_TRUE(rsp); + + int status; + ConstElementPtr cfg = parseAnswer(status, rsp); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status); + + EXPECT_FALSE(server_->network_state_.isServiceEnabled()); +} + +// This test verifies that it is possible to disable DHCP service for a short +// period of time, after which the service is automatically enabled. +TEST_F(CtrlChannelDhcpv6SrvTest, dhcpDisableTemporarily) { + createUnixChannelServer(); + std::string response; + + // Send a command to disable DHCP service for 3 seconds. + sendUnixCommand("{" + " \"command\": \"dhcp-disable\"," + " \"arguments\": {" + " \"max-period\": 3" + " }" + "}", response); + ConstElementPtr rsp; + + // The response should be a valid JSON. + EXPECT_NO_THROW(rsp = Element::fromJSON(response)); + ASSERT_TRUE(rsp); + + int status; + ConstElementPtr cfg = parseAnswer(status, rsp); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status); + + // The service should be disabled. + EXPECT_FALSE(server_->network_state_.isServiceEnabled()); + // And the timer should be scheduled which counts the time to automatic + // enabling of the service. + EXPECT_TRUE(server_->network_state_.isDelayedEnableAll()); +} + +// This test verifies if it is possible to enable DHCP service via command. +TEST_F(CtrlChannelDhcpv6SrvTest, dhcpEnable) { + createUnixChannelServer(); + std::string response; + + sendUnixCommand("{ \"command\": \"dhcp-enable\" }", response); + ConstElementPtr rsp; + + // The response should be a valid JSON. + EXPECT_NO_THROW(rsp = Element::fromJSON(response)); + ASSERT_TRUE(rsp); + + int status; + ConstElementPtr cfg = parseAnswer(status, rsp); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status); + + EXPECT_TRUE(server_->network_state_.isServiceEnabled()); +} + /// Verify that concurrent connections over the control channel can be /// established. /// @todo Future Kea 1.3 tickets will modify the behavior of the CommandMgr