]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5442] Implemented 'dhcp-disable' and 'dhcp-enable' commands for DHCPv6.
authorMarcin Siodelski <marcin@isc.org>
Mon, 4 Dec 2017 14:04:47 +0000 (15:04 +0100)
committerMarcin Siodelski <marcin@isc.org>
Mon, 4 Dec 2017 14:04:47 +0000 (15:04 +0100)
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/bin/dhcp6/ctrl_dhcp6_srv.h
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc

index 87bf60bfde3cd895dc5b7b9b0ca65d20b3e83d7a..eeadd5e70d99d94218d4b0810e35d4177f7eb19b 100644 (file)
@@ -20,6 +20,7 @@
 #include <stats/stats_mgr.h>
 #include <cfgrpt/config_report.h>
 #include <signal.h>
+#include <sstream>
 
 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<unsigned>(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");
index 4648aefb5c37f94067ca92e96b668ea8157c10aa..21d7e7493d5deb0a3c80ba56b8d6862305b5528b 100644 (file)
@@ -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
index 9e24fdb24932d488e2ecefdc329ce38a4ee0870a..b105e5557d0a29633985acde6f2dbb31f8edc482 100644 (file)
@@ -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