Parcourir la source

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

Marcin Siodelski il y a 12 ans
Parent
commit
9f8d746079

+ 0 - 1
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -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>

+ 40 - 1
src/bin/dhcp6/ctrl_dhcp6_srv.cc

@@ -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);
+}
 
 };
 };

+ 11 - 0
src/bin/dhcp6/ctrl_dhcp6_srv.h

@@ -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_;
 

+ 2 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -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);

+ 15 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -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

+ 1 - 1
src/lib/dhcp/iface_mgr.cc

@@ -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;
         }