]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3062] compute iface flags on redetect
authorRazvan Becheriu <razvan@isc.org>
Thu, 12 Feb 2026 18:25:18 +0000 (20:25 +0200)
committerRazvan Becheriu <razvan@isc.org>
Wed, 18 Feb 2026 12:05:50 +0000 (14:05 +0200)
src/lib/dhcpsrv/cfg_iface.cc
src/lib/dhcpsrv/cfg_iface.h

index 4787f2b8603ab40db7f12f3d233e97eecc406322..5cd92da551b81a06fdf3a7712ab1837c9a7d8f7f 100644 (file)
@@ -63,39 +63,10 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
     // Close any open sockets because we're going to modify some properties
     // of the IfaceMgr. Those modifications require that sockets are closed.
     closeSockets();
-    // The loopback interface can be used only when:
-    //  - UDP socket will be used, i.e. not IPv4 and RAW socket
-    //  - the loopback interface is in the interface set or the address map.
-    bool loopback_used_ = false;
-    if ((family == AF_INET6) || (socket_type_ == SOCKET_UDP)) {
-        // Check interface set
-        for (auto const& iface_name : iface_set_) {
-            IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
-            if (iface && iface->flag_loopback_) {
-                loopback_used_ = true;
-            }
-        }
-        // Check address map
-        for (auto const& unicast : address_map_) {
-            IfacePtr iface = IfaceMgr::instance().getIface(unicast.first);
-            if (iface && iface->flag_loopback_) {
-                loopback_used_ = true;
-            }
-        }
-    }
-    // If wildcard interface '*' was not specified, set all interfaces to
-    // inactive state. We will later enable them selectively using the
-    // interface names specified by the user. If wildcard interface was
-    // specified, mark all interfaces active. Mark loopback inactive when
-    // not explicitly allowed.
-    setState(family, !wildcard_used_, !loopback_used_);
-    IfaceMgr& iface_mgr = IfaceMgr::instance();
-    // Remove selection of unicast addresses from all interfaces.
-    iface_mgr.clearUnicasts();
+
     // Initialize IfaceMgr FDEventHandler.
-    iface_mgr.initializeFDEventHandler();
-    // Allow the loopback interface when required.
-    iface_mgr.setAllowLoopBack(loopback_used_);
+    IfaceMgr::instance().initializeFDEventHandler();
+
     // For the DHCPv4 server, if the user has selected that raw sockets
     // should be used, we will try to configure the Interface Manager to
     // support the direct responses to the clients that don't have the
@@ -103,70 +74,17 @@ CfgIface::openSockets(const uint16_t family, const uint16_t port,
     // sockets. However, this may be unsupported on some operating
     // systems, so there is no guarantee.
     if ((family == AF_INET) && (!IfaceMgr::instance().isTestMode())) {
-        iface_mgr.setMatchingPacketFilter(socket_type_ == SOCKET_RAW);
+        IfaceMgr::instance().setMatchingPacketFilter(socket_type_ == SOCKET_RAW);
         if ((socket_type_ == SOCKET_RAW) &&
-            !iface_mgr.isDirectResponseSupported()) {
+            !IfaceMgr::instance().isDirectResponseSupported()) {
             LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_SOCKET_RAW_UNSUPPORTED);
         }
     }
-    // If there is no wildcard interface specified, we will have to iterate
-    // over the names specified by the caller and enable them.
-    if (!wildcard_used_) {
-        for (auto const& iface_name : iface_set_) {
-            IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
-            // This shouldn't really happen because we are checking the
-            // names of interfaces when they are being added (use()
-            // function). But, if someone has triggered detection of
-            // interfaces since then, some interfaces may have disappeared.
-            if (iface == NULL) {
-                isc_throw(Unexpected,
-                          "fail to open socket on interface '"
-                          << iface_name << "' as this interface doesn't"
-                          " exist");
-
-            } else if (family == AF_INET) {
-                iface->inactive4_ = false;
-                setIfaceAddrsState(family, true, *iface);
-
-            } else {
-                iface->inactive6_ = false;
-            }
-        }
-    }
-
-    // Select unicast sockets for DHCPv6 or activate specific IPv4 addresses
-    // for DHCPv4.
-    for (auto const& unicast : address_map_) {
-        IfacePtr iface = IfaceMgr::instance().getIface(unicast.first);
-        if (iface == NULL) {
-            isc_throw(Unexpected,
-                      "fail to open unicast socket on interface '"
-                      << unicast.first << "' as this interface doesn't"
-                      " exist");
-        }
-        if (family == AF_INET6) {
-            iface->addUnicast(unicast.second);
-            iface->inactive6_ = false;
-
-        } else {
-            iface->setActive(unicast.second, true);
-            iface->inactive4_ = false;
-        }
-    }
 
     // Use broadcast only if we're using raw sockets. For the UDP sockets,
     // we only handle the relayed (unicast) traffic.
     const bool can_use_bcast = use_bcast && (socket_type_ == SOCKET_RAW);
 
-    // Opening multiple raw sockets handling brodcast traffic on the single
-    // interface may lead to processing the same message multiple times.
-    // We don't prohibit such configuration because raw sockets can as well
-    // handle the relayed traffic. We have to issue a warning, however, to
-    // draw administrator's attention.
-    if (family == AF_INET && can_use_bcast && multipleAddressesPerInterfaceActive()) {
-        LOG_WARN(dhcpsrv_logger, DHCPSRV_MULTIPLE_RAW_SOCKETS_PER_IFACE);
-    }
-
     reconnect_ctl_ = makeReconnectCtl();
     auto sopen = openSocketsWithRetry(reconnect_ctl_, family, port, can_use_bcast);
 
@@ -189,8 +107,6 @@ CfgIface::openSocketsForFamily(const uint16_t family, const uint16_t port,
         no_errors = false;
     };
 
-    IfaceMgr::instance().detectIfaces(true);
-
     bool sopen = false;
     if (family == AF_INET) {
         sopen = IfaceMgr::instance().openSockets4(port, can_use_bcast,
@@ -225,12 +141,103 @@ ReconnectCtlPtr CfgIface::makeReconnectCtl() const {
 bool
 CfgIface::openSocketsWithRetry(ReconnectCtlPtr reconnect_ctl,
                                const uint16_t family, const uint16_t port,
-                               const bool can_use_bcast) {
+                               const bool can_use_bcast) const {
     MultiThreadingCriticalSection cs;
 
+    // Remove selection of unicast addresses from all interfaces.
+    IfaceMgr::instance().clearUnicasts();
+
+    // The loopback interface can be used only when:
+    //  - UDP socket will be used, i.e. not IPv4 and RAW socket
+    //  - the loopback interface is in the interface set or the address map.
+    bool loopback_used = false;
+    if ((family == AF_INET6) || (socket_type_ == SOCKET_UDP)) {
+        // Check interface set
+        for (auto const& iface_name : iface_set_) {
+            IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
+            if (iface && iface->flag_loopback_) {
+                loopback_used = true;
+            }
+        }
+        // Check address map
+        for (auto const& unicast : address_map_) {
+            IfacePtr iface = IfaceMgr::instance().getIface(unicast.first);
+            if (iface && iface->flag_loopback_) {
+                loopback_used = true;
+            }
+        }
+    }
+    // Allow the loopback interface when required.
+    IfaceMgr::instance().setAllowLoopBack(loopback_used);
+
+    // If wildcard interface '*' was not specified, set all interfaces to
+    // inactive state. We will later enable them selectively using the
+    // interface names specified by the user. If wildcard interface was
+    // specified, mark all interfaces active. Mark loopback inactive when
+    // not explicitly allowed.
+    setState(family, !wildcard_used_, !loopback_used);
+
+    // If there is no wildcard interface specified, we will have to iterate
+    // over the names specified by the caller and enable them.
+    if (!wildcard_used_) {
+        for (auto const& iface_name : iface_set_) {
+            IfacePtr iface = IfaceMgr::instance().getIface(iface_name);
+
+            // This shouldn't really happen because we are checking the
+            // names of interfaces when they are being added (use()
+            // function). But, if someone has triggered detection of
+            // interfaces since then, some interfaces may have disappeared.
+            if (iface == NULL) {
+                isc_throw(Unexpected,
+                          "fail to open socket on interface '"
+                          << iface_name << "' as this interface doesn't"
+                          " exist");
+            }
+            if (family == AF_INET) {
+                iface->inactive4_ = false;
+                setIfaceAddrsState(family, true, *iface);
+
+            } else {
+                iface->inactive6_ = false;
+            }
+        }
+    }
+
+    // Select unicast sockets for DHCPv6 or activate specific IPv4 addresses
+    // for DHCPv4.
+    for (auto const& unicast : address_map_) {
+        IfacePtr iface = IfaceMgr::instance().getIface(unicast.first);
+        if (iface == NULL) {
+            isc_throw(Unexpected,
+                      "fail to open unicast socket on interface '"
+                      << unicast.first << "' as this interface doesn't"
+                      " exist");
+        }
+        if (family == AF_INET6) {
+            iface->addUnicast(unicast.second);
+            iface->inactive6_ = false;
+
+        } else {
+            iface->setActive(unicast.second, true);
+            iface->inactive4_ = false;
+        }
+    }
+
+    // Opening multiple raw sockets handling brodcast traffic on the single
+    // interface may lead to processing the same message multiple times.
+    // We don't prohibit such configuration because raw sockets can as well
+    // handle the relayed traffic. We have to issue a warning, however, to
+    // draw administrator's attention.
+    if (family == AF_INET && can_use_bcast &&
+        CfgIface::multipleAddressesPerInterfaceActive()) {
+        LOG_WARN(dhcpsrv_logger, DHCPSRV_MULTIPLE_RAW_SOCKETS_PER_IFACE);
+    }
+
+    IfaceMgr::instance().detectIfaces(true);
+
     // Skip opened sockets in the retry calls.
     bool is_initial_call = (reconnect_ctl->retriesLeft() == reconnect_ctl->maxRetries());
-    auto result_pair = openSocketsForFamily(family, port, can_use_bcast, !is_initial_call);
+    auto result_pair = CfgIface::openSocketsForFamily(family, port, can_use_bcast, !is_initial_call);
     bool sopen = result_pair.first;
     bool has_errors = !result_pair.second;
 
@@ -249,6 +256,7 @@ CfgIface::openSocketsWithRetry(ReconnectCtlPtr reconnect_ctl,
         if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
             TimerMgr::instance()->registerTimer(timer_name,
                                                 std::bind(&CfgIface::openSocketsWithRetry,
+                                                          this,
                                                           reconnect_ctl, family,
                                                           port, can_use_bcast),
                                                 reconnect_ctl->retryInterval(),
index d88884aa6b75b1993c0af282ffb1f45773d1d170..fe5fc1d399dbecf6dafed7a5e7158da88da946cb 100644 (file)
@@ -453,9 +453,9 @@ private:
     /// traffic. This parameter is ignored for IPv6.
     ///
     /// @return True if at least one socket opened successfully.
-    static bool openSocketsWithRetry(util::ReconnectCtlPtr reconnect_ctl,
-                                     const uint16_t family, const uint16_t port,
-                                     const bool can_use_bcast);
+    bool openSocketsWithRetry(util::ReconnectCtlPtr reconnect_ctl,
+                              const uint16_t family, const uint16_t port,
+                              const bool can_use_bcast) const;
 
     /// @brief Represents a set of interface names.
     typedef std::set<std::string> IfaceSet;