Parcourir la source

[2765] Added fallback socket descriptor to SocketInfo structure.

Marcin Siodelski il y a 11 ans
Parent
commit
4e225668a6

+ 5 - 3
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -20,6 +20,7 @@
 #define DHCP4_TEST_UTILS_H
 
 #include <gtest/gtest.h>
+#include <dhcp/iface_mgr.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt_filter.h>
 #include <dhcp/pkt_filter_inet.h>
@@ -52,9 +53,10 @@ public:
     }
 
     /// Does nothing.
-    virtual int openSocket(const Iface&, const isc::asiolink::IOAddress&,
-                           const uint16_t, const bool, const bool) {
-        return (0);
+    virtual SocketInfo openSocket(const Iface&,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port, const bool, const bool) {
+        return (SocketInfo(addr, port, 0));
     }
 
     /// Does nothing.

+ 4 - 6
src/lib/dhcp/iface_mgr.cc

@@ -741,7 +741,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
         }
     }
 
-    SocketInfo info(sock, addr, port);
+    SocketInfo info(addr, port, sock);
     iface.addSocket(info);
 
     return (sock);
@@ -754,13 +754,11 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr,
     // Skip checking if the packet_filter_ is non-NULL because this check
     // has been already done when packet filter object was set.
 
-    int sock = packet_filter_->openSocket(iface, addr, port,
-                                          receive_bcast, send_bcast);
-
-    SocketInfo info(sock, addr, port);
+    SocketInfo info = packet_filter_->openSocket(iface, addr, port,
+                                                 receive_bcast, send_bcast);
     iface.addSocket(info);
 
-    return (sock);
+    return (info.sockfd_);
 }
 
 bool

+ 37 - 7
src/lib/dhcp/iface_mgr.h

@@ -72,19 +72,49 @@ public:
 
 /// Holds information about socket.
 struct SocketInfo {
-    uint16_t sockfd_; /// socket descriptor
+
     isc::asiolink::IOAddress addr_; /// bound address
     uint16_t port_;   /// socket port
     uint16_t family_; /// IPv4 or IPv6
 
+    /// @brief Socket descriptor (a.k.a. primary socket).
+    int sockfd_;
+
+    /// @brief Fallback socket descriptor.
+    ///
+    /// This socket descriptor holds the handle to the fallback socket.
+    /// The fallback socket is created when there is a need for the regular
+    /// datagram socket to be bound to an IP address and port, besides
+    /// primary socket (sockfd_) which is actually used to receive and process
+    /// the DHCP messages. The fallback socket (if exists) is always associated
+    /// with the primary socket. In particular, the need for the fallback socket
+    /// arises when raw socket is a primary one. When primary socket is open,
+    /// it is bound to an interface not the address and port. The implications
+    /// include the possibility that the other process (e.g. the other instance
+    /// of DHCP server) will bind to the same address and port through which the
+    /// raw socket receives the DHCP messages.Another implication is that the
+    /// kernel, being unaware of the DHCP server operating through the raw
+    /// socket, will respond with the ICMP "Destination port unreachable"
+    /// messages when DHCP messages are only received through the raw socket.
+    /// In order to workaround the issues mentioned here, the fallback socket
+    /// should be opened so as/ the kernel is aware that the certain address
+    /// and port is in use.
+    ///
+    /// The fallback description is supposed to be set to a negative value if
+    /// the fallback socket is closed (not open).
+    int fallbackfd_;
+
     /// @brief SocketInfo constructor.
     ///
-    /// @param sockfd socket descriptor
-    /// @param addr an address the socket is bound to
-    /// @param port a port the socket is bound to
-    SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
-               uint16_t port)
-        :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
+    /// @param addr An address the socket is bound to.
+    /// @param port A port the socket is bound to.
+    /// @param sockfd Socket descriptor.
+    /// @param fallbackfd A descriptor of the fallback socket.
+    SocketInfo(const isc::asiolink::IOAddress& addr, const uint16_t port,
+               const int sockfd, const int fallbackfd = -1)
+        : addr_(addr), port_(port), family_(addr.getFamily()),
+          sockfd_(sockfd), fallbackfd_(fallbackfd) { }
+
 };
 
 

+ 21 - 11
src/lib/dhcp/pkt_filter.h

@@ -67,20 +67,30 @@ public:
     /// @return true of the direct response is supported.
     virtual bool isDirectResponseSupported() const = 0;
 
-    /// @brief Open socket.
+    /// @brief Open primary and fallback socket.
     ///
-    /// @param iface interface descriptor
-    /// @param addr address on the interface to be used to send packets.
-    /// @param port port number.
-    /// @param receive_bcast configure socket to receive broadcast messages
+    /// A method implementation in the derived class may open one or two
+    /// sockets:
+    /// - a primary socket - used for communication with clients. DHCP messages
+    /// received using this socket are processed and the same socket is used
+    /// to send a response to the client.
+    /// - a fallback socket which is optionally opened if there is a need for
+    /// the presence of the socket which can be bound to a specific IP address
+    /// and UDP port (e.g. raw primary socket can't be). For the details, see
+    /// the documentation of @c isc::dhcp::SocketInfo.
+    ///
+    /// @param iface Interface descriptor.
+    /// @param addr Address on the interface to be used to send packets.
+    /// @param port Port number.
+    /// @param receive_bcast Configure socket to receive broadcast messages
     /// @param send_bcast configure socket to send broadcast messages.
     ///
-    /// @return created socket's descriptor
-    virtual int openSocket(const Iface& iface,
-                           const isc::asiolink::IOAddress& addr,
-                           const uint16_t port,
-                           const bool receive_bcast,
-                           const bool send_bcast) = 0;
+    /// @return A structure describing a primary and fallback socket.
+    virtual SocketInfo openSocket(const Iface& iface,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port,
+                                  const bool receive_bcast,
+                                  const bool send_bcast) = 0;
 
     /// @brief Receive packet over specified socket.
     ///

+ 8 - 6
src/lib/dhcp/pkt_filter_inet.cc

@@ -28,11 +28,12 @@ PktFilterInet::PktFilterInet()
 {
 }
 
-int PktFilterInet::openSocket(const Iface& iface,
-                              const isc::asiolink::IOAddress& addr,
-                              const uint16_t port,
-                              const bool receive_bcast,
-                              const bool send_bcast) {
+SocketInfo
+PktFilterInet::openSocket(const Iface& iface,
+                          const isc::asiolink::IOAddress& addr,
+                          const uint16_t port,
+                          const bool receive_bcast,
+                          const bool send_bcast) {
 
     struct sockaddr_in addr4;
     memset(&addr4, 0, sizeof(sockaddr));
@@ -90,7 +91,8 @@ int PktFilterInet::openSocket(const Iface& iface,
     }
 #endif
 
-    return (sock);
+    SocketInfo sock_desc(addr, port, sock);
+    return (sock_desc);
 
 }
 

+ 12 - 12
src/lib/dhcp/pkt_filter_inet.h

@@ -44,20 +44,20 @@ public:
         return (false);
     }
 
-    /// @brief Open socket.
+    /// @brief Open primary and fallback socket.
     ///
-    /// @param iface interface descriptor
-    /// @param addr address on the interface to be used to send packets.
-    /// @param port port number.
-    /// @param receive_bcast configure socket to receive broadcast messages
-    /// @param send_bcast configure socket to send broadcast messages.
+    /// @param iface Interface descriptor.
+    /// @param addr Address on the interface to be used to send packets.
+    /// @param port Port number.
+    /// @param receive_bcast Configure socket to receive broadcast messages
+    /// @param send_bcast Configure socket to send broadcast messages.
     ///
-    /// @return created socket's descriptor
-    virtual int openSocket(const Iface& iface,
-                           const isc::asiolink::IOAddress& addr,
-                           const uint16_t port,
-                           const bool receive_bcast,
-                           const bool send_bcast);
+    /// @return A structure describing a primary and fallback socket.
+    virtual SocketInfo openSocket(const Iface& iface,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port,
+                                  const bool receive_bcast,
+                                  const bool send_bcast);
 
     /// @brief Receive packet over specified socket.
     ///

+ 4 - 3
src/lib/dhcp/pkt_filter_lpf.cc

@@ -102,7 +102,7 @@ using namespace isc::util;
 namespace isc {
 namespace dhcp {
 
-int
+SocketInfo
 PktFilterLPF::openSocket(const Iface& iface,
                          const isc::asiolink::IOAddress& addr,
                          const uint16_t port, const bool,
@@ -123,7 +123,7 @@ PktFilterLPF::openSocket(const Iface& iface,
         // We return negative, the proper error message will be displayed
         // by the IfaceMgr ...
         close(sock_check);
-        return (-1);
+        return (SocketInfo(addr, port, -1));
     }
     close(sock_check);
 
@@ -166,7 +166,8 @@ PktFilterLPF::openSocket(const Iface& iface,
                   << "' to interface '" << iface.getName() << "'");
     }
 
-    return (sock);
+    SocketInfo sock_desc(addr, port, sock);
+    return (sock_desc);
 
 }
 

+ 12 - 13
src/lib/dhcp/pkt_filter_lpf.h

@@ -41,21 +41,20 @@ public:
         return (true);
     }
 
-    /// @brief Open socket.
+    /// @brief Open primary and fallback socket.
     ///
-    /// @param iface interface descriptor
-    /// @param addr address on the interface to be used to send packets.
-    /// @param port port number.
-    /// @param receive_bcast configure socket to receive broadcast messages
-    /// @param send_bcast configure socket to send broadcast messages.
+    /// @param iface Interface descriptor.
+    /// @param addr Address on the interface to be used to send packets.
+    /// @param port Port number.
+    /// @param receive_bcast Configure socket to receive broadcast messages
+    /// @param send_bcast Configure socket to send broadcast messages.
     ///
-    /// @throw isc::NotImplemented always
-    /// @return created socket's descriptor
-    virtual int openSocket(const Iface& iface,
-                           const isc::asiolink::IOAddress& addr,
-                           const uint16_t port,
-                           const bool receive_bcast,
-                           const bool send_bcast);
+    /// @return A structure describing a primary and fallback socket.
+    virtual SocketInfo openSocket(const Iface& iface,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port,
+                                  const bool receive_bcast,
+                                  const bool send_bcast);
 
     /// @brief Receive packet over specified socket.
     ///

+ 24 - 12
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -84,13 +84,13 @@ public:
     /// (because real values are rather less than 255). Values greater
     /// than 255 are not recommended because they cause warnings to be
     /// reported by Valgrind when invoking close() on them.
-    virtual int openSocket(const Iface&,
-                           const isc::asiolink::IOAddress&,
-                           const uint16_t,
-                           const bool,
-                           const bool) {
+    virtual SocketInfo openSocket(const Iface&,
+                                  const isc::asiolink::IOAddress& addr,
+                                  const uint16_t port,
+                                  const bool,
+                                  const bool) {
         open_socket_called_ = true;
-        return (255);
+        return (SocketInfo(addr, port, 255));
     }
 
     /// Does nothing
@@ -1152,18 +1152,28 @@ TEST_F(IfaceMgrTest, iface_methods) {
 TEST_F(IfaceMgrTest, socketInfo) {
 
     // Check that socketinfo for IPv4 socket is functional
-    SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
+    SocketInfo sock1(IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7, 7);
     EXPECT_EQ(7, sock1.sockfd_);
+    EXPECT_EQ(-1, sock1.fallbackfd_);
     EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
     EXPECT_EQ(AF_INET, sock1.family_);
     EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
 
+    // Check that non-default value of the fallback socket descriptor is set
+    SocketInfo sock2(IOAddress("192.0.2.53"), DHCP4_SERVER_PORT + 8, 8, 10);
+    EXPECT_EQ(8, sock2.sockfd_);
+    EXPECT_EQ(10, sock2.fallbackfd_);
+    EXPECT_EQ("192.0.2.53", sock2.addr_.toText());
+    EXPECT_EQ(AF_INET, sock2.family_);
+    EXPECT_EQ(DHCP4_SERVER_PORT + 8, sock2.port_);
+
     // Check that socketinfo for IPv6 socket is functional
-    SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
-    EXPECT_EQ(9, sock2.sockfd_);
-    EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
-    EXPECT_EQ(AF_INET6, sock2.family_);
-    EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock2.port_);
+    SocketInfo sock3(IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9, 9);
+    EXPECT_EQ(9, sock3.sockfd_);
+    EXPECT_EQ(-1, sock3.fallbackfd_);
+    EXPECT_EQ("2001:db8:1::56", sock3.addr_.toText());
+    EXPECT_EQ(AF_INET6, sock3.family_);
+    EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock3.port_);
 
     // Now let's test if IfaceMgr handles socket info properly
     scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
@@ -1171,6 +1181,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
     ASSERT_TRUE(loopback);
     loopback->addSocket(sock1);
     loopback->addSocket(sock2);
+    loopback->addSocket(sock3);
 
     Pkt6 pkt6(DHCPV6_REPLY, 123456);
 
@@ -1225,6 +1236,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
 
     EXPECT_NO_THROW(
         ifacemgr->getIface(LOOPBACK)->delSocket(7);
+        ifacemgr->getIface(LOOPBACK)->delSocket(8);
     );
 
     // It should throw again, there's no usable socket anymore.

+ 4 - 4
src/lib/dhcp/tests/pkt_filter_inet_unittest.cc

@@ -112,7 +112,7 @@ TEST_F(PktFilterInetTest, openSocket) {
 
     // Try to open socket.
     PktFilterInet pkt_filter;
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     // Check that socket has been opened.
     ASSERT_GE(socket_, 0);
 
@@ -170,7 +170,7 @@ TEST_F(PktFilterInetTest, send) {
     // Open socket. We don't check that the socket has appropriate
     // options and family set because we have checked that in the
     // openSocket test already.
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     ASSERT_GE(socket_, 0);
 
     // Send the packet over the socket.
@@ -249,14 +249,14 @@ TEST_F(PktFilterInetTest, receive) {
     // Open socket. We don't check that the socket has appropriate
     // options and family set because we have checked that in the
     // openSocket test already.
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     ASSERT_GE(socket_, 0);
 
     // Send the packet over the socket.
     ASSERT_NO_THROW(pkt_filter.send(iface, socket_, pkt));
 
     // Receive the packet.
-    SocketInfo socket_info(socket_, IOAddress("127.0.0.1"), PORT);
+    SocketInfo socket_info(IOAddress("127.0.0.1"), PORT, socket_);
     Pkt4Ptr rcvd_pkt = pkt_filter.receive(iface, socket_info);
     // Check that the packet has been correctly received.
     ASSERT_TRUE(rcvd_pkt);

+ 3 - 3
src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc

@@ -124,7 +124,7 @@ TEST_F(PktFilterLPFTest, DISABLED_openSocket) {
 
     // Try to open socket.
     PktFilterLPF pkt_filter;
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     // Check that socket has been opened.
     ASSERT_GE(socket_, 0);
 
@@ -183,7 +183,7 @@ TEST_F(PktFilterLPFTest, DISABLED_send) {
     // Open socket. We don't check that the socket has appropriate
     // options and family set because we have checked that in the
     // openSocket test already.
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     ASSERT_GE(socket_, 0);
 
     // Send the packet over the socket.
@@ -273,7 +273,7 @@ TEST_F(PktFilterLPFTest, DISABLED_receive) {
     // Open socket. We don't check that the socket has appropriate
     // options and family set because we have checked that in the
     // openSocket test already.
-    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
+    socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
     ASSERT_GE(socket_, 0);
 
     // Send the packet over the socket.