BIND 10 trac2902, updated. 80f01bc608cbd779c76a6e5d5ca8dade8b37dbdd [2902] Implemented selective closure of sockets (e.g. only v4 sockets).

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Apr 26 12:37:08 UTC 2013


The branch, trac2902 has been updated
       via  80f01bc608cbd779c76a6e5d5ca8dade8b37dbdd (commit)
      from  1ca6a3ac00cdf22e6fea1157bc887dd44e1f87a7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 80f01bc608cbd779c76a6e5d5ca8dade8b37dbdd
Author: Marcin Siodelski <marcin at isc.org>
Date:   Fri Apr 26 14:36:56 2013 +0200

    [2902] Implemented selective closure of sockets (e.g. only v4 sockets).

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dhcp/iface_mgr.cc                |   49 +++++++++++++++++--
 src/lib/dhcp/iface_mgr.h                 |   44 ++++++++++++++++-
 src/lib/dhcp/tests/iface_mgr_unittest.cc |   78 ++++++++++++++++++++++++++++++
 3 files changed, 166 insertions(+), 5 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index ded2639..b5c155b 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -58,11 +58,44 @@ Iface::Iface(const std::string& name, int ifindex)
 
 void
 Iface::closeSockets() {
-    for (SocketCollection::iterator sock = sockets_.begin();
-         sock != sockets_.end(); ++sock) {
-        close(sock->sockfd_);
+    // Close IPv4 sockets.
+    closeSockets(AF_INET);
+    // Close IPv6 sockets.
+    closeSockets(AF_INET6);
+}
+
+void
+Iface::closeSockets(const uint16_t family) {
+    // Check that the correect 'family' value has been specified.
+    // The possible values are AF_INET or AF_INET6. Note that, in
+    // the current code they are used to differentiate that the
+    // socket is used to transmit IPv4 or IPv6 traffic. However,
+    // the actual family types of the sockets may be different,
+    // e.g. for LPF we are using raw sockets of AF_PACKET family.
+    //
+    // @todo Consider replacing the AF_INET and AF_INET6 with some
+    // enum which will not be confused with the actual socket type.
+    if ((family != AF_INET) && (family != AF_INET6)) {
+        isc_throw(BadValue, "Invalid socket family " << family
+                  << " specified when requested to close all sockets"
+                  << " which belong to this family");
+    }
+    // Search for the socket of the specific type.
+    SocketCollection::iterator sock = sockets_.begin();
+    while (sock != sockets_.end()) {
+        if (sock->family_ == family) {
+            // Close and delete the socket and move to the
+            // next one.
+            close(sock->sockfd_);
+            sockets_.erase(sock++);
+
+        } else {
+            // Different type of socket. Let's move
+            // to the next one.
+            ++sock;
+
+        }
     }
-    sockets_.clear();
 }
 
 std::string
@@ -150,6 +183,14 @@ void IfaceMgr::closeSockets() {
     }
 }
 
+void
+IfaceMgr::closeSockets(const uint16_t family) {
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end(); ++iface) {
+        iface->closeSockets(family);
+    }
+}
+
 IfaceMgr::~IfaceMgr() {
     // control_buf_ is deleted automatically (scoped_ptr)
     control_buf_len_ = 0;
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 5c40fea..7dd8bac 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -110,6 +110,27 @@ public:
     /// @brief Closes all open sockets on interface.
     void closeSockets();
 
+    /// @brief Closes all IPv4 or IPv6 sockets.
+    ///
+    /// This function closes sockets of the specific 'type' and closes them.
+    /// The 'type' of the socket indicates whether it is used to send IPv4
+    /// or IPv6 packets. The allowed values of the parameter are AF_INET and
+    /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
+    /// to realize that the actual types of sockets may be different than
+    /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
+    /// always used AF_INET sockets for IPv4 traffic. This is no longer the
+    /// case when the Direct IPv4 traffic must be supported. In order to support
+    /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
+    /// family sockets on Linux.
+    ///
+    /// @todo Replace the AF_INET and AF_INET6 values with an enum
+    /// which will not be confused with the actual socket type.
+    ///
+    /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
+    ///
+    /// @throw BadValue if family value is different than AF_INET or AF_INET6.
+    void closeSockets(const uint16_t family);
+
     /// @brief Returns full interface name as "ifname/ifindex" string.
     ///
     /// @return string with interface name
@@ -268,7 +289,7 @@ public:
     /// flag specifies if selected interface is multicast capable
     bool flag_multicast_;
 
-    /// flag specifies if selected interface is broadcast capable
+   /// flag specifies if selected interface is broadcast capable
     bool flag_broadcast_;
 
     /// interface flags (this value is as is returned by OS,
@@ -538,6 +559,27 @@ public:
     /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
     void closeSockets();
 
+    /// @brief Closes all IPv4 or IPv6 sockets.
+    ///
+    /// This function closes sockets of the specific 'type' and closes them.
+    /// The 'type' of the socket indicates whether it is used to send IPv4
+    /// or IPv6 packets. The allowed values of the parameter are AF_INET and
+    /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
+    /// to realize that the actual types of sockets may be different than
+    /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
+    /// always used AF_INET sockets for IPv4 traffic. This is no longer the
+    /// case when the Direct IPv4 traffic must be supported. In order to support
+    /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
+    /// family sockets on Linux.
+    ///
+    /// @todo Replace the AF_INET and AF_INET6 values with an enum
+    /// which will not be confused with the actual socket type.
+    ///
+    /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
+    ///
+    /// @throw BadValue if family value is different than AF_INET or AF_INET6.
+    void closeSockets(const uint16_t family);
+
     /// @brief returns number of detected interfaces
     ///
     /// @return number of detected interfaces
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index ea14311..e2e5191 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -122,6 +122,24 @@ public:
     ~IfaceMgrTest() {
     }
 
+    // Get ther number of IPv4 or IPv6 sockets on the loopback interface
+    int getOpenSocketsCount(const Iface& iface, uint16_t family) const {
+        // Get all sockets.
+        Iface::SocketCollection sockets = iface.getSockets();
+
+        // Loop through sockets and try to find the ones which match the
+        // specified type.
+        int sockets_count = 0;
+        for (Iface::SocketCollection::const_iterator sock = sockets.begin();
+             sock != sockets.end(); ++sock) {
+            // Match found, increase the counter.
+            if (sock->family_ == family) {
+                ++sockets_count;
+            }
+        }
+        return (sockets_count);
+    }
+
 };
 
 // We need some known interface to work reliably. Loopback interface
@@ -216,6 +234,66 @@ TEST_F(IfaceMgrTest, basic) {
     ASSERT_TRUE(&ifacemgr != 0);
 }
 
+
+// This test verifies that sockets can be closed selectively, i.e. all
+// IPv4 sockets can be closed first and all IPv6 sockets remain open.
+TEST_F(IfaceMgrTest, closeSockets) {
+    // Will be using local loopback addresses for this test.
+    IOAddress loaddr("127.0.0.1");
+    IOAddress loaddr6("::1");
+
+    // Create instance of IfaceMgr.
+    boost::scoped_ptr<NakedIfaceMgr> iface_mgr(new NakedIfaceMgr());
+    ASSERT_TRUE(iface_mgr);
+
+    // Out constructor does not detect interfaces by itself. We need
+    // to create one and add.
+    int ifindex = if_nametoindex(LOOPBACK);
+    ASSERT_GT(ifindex, 0);
+    Iface lo_iface(LOOPBACK, ifindex);
+    iface_mgr->getIfacesLst().push_back(lo_iface);
+
+    // Create set of V4 and V6 sockets on the loopback interface.
+    // They must differ by a port they are bound to.
+    for (int i = 0; i < 6; ++i) {
+        // Every other socket will be IPv4.
+        if (i % 2) {
+            ASSERT_NO_THROW(
+                iface_mgr->openSocket(LOOPBACK, loaddr, 10000 + i)
+            );
+        } else {
+            ASSERT_NO_THROW(
+                iface_mgr->openSocket(LOOPBACK, loaddr6, 10000 + i)
+            );
+        }
+    }
+
+    // At the end we should have 3 IPv4 and 3 IPv6 sockets open.
+    Iface* iface = iface_mgr->getIface(LOOPBACK);
+    ASSERT_TRUE(iface != NULL);
+
+    int v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+    ASSERT_EQ(3, v4_sockets_count);
+    int v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+    ASSERT_EQ(3, v6_sockets_count);
+
+    // Let's try to close only IPv4 sockets.
+    ASSERT_NO_THROW(iface_mgr->closeSockets(AF_INET));
+    v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+    EXPECT_EQ(0, v4_sockets_count);
+    // The IPv6 sockets should remain open.
+    v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+    EXPECT_EQ(3, v6_sockets_count);
+
+    // Let's try to close IPv6 sockets.
+    ASSERT_NO_THROW(iface_mgr->closeSockets(AF_INET6));
+    v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+    EXPECT_EQ(0, v4_sockets_count);
+    // They should have been closed now.
+    v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+    EXPECT_EQ(0, v6_sockets_count);
+}
+
 TEST_F(IfaceMgrTest, ifaceClass) {
     // basic tests for Iface inner class
 



More information about the bind10-changes mailing list