]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add support for FreeBSD's SO_REUSEPORT_LB 9157/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 26 May 2020 08:50:26 +0000 (10:50 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 26 May 2020 08:50:26 +0000 (10:50 +0200)
On FreeBSD, SO_REUSEPORT "permits multiple instances of a program to each
receive UDP/IP multicast or broadcast datagrams destined for the bound port",
while SO_REUSEPORT_LB distributes them "among the sharing processes based on
a hash function of local port number, foreign IP address and port number".

pdns/Makefile.am
pdns/dnsdist.cc
pdns/dumresp.cc
pdns/iputils.cc
pdns/iputils.hh
pdns/nameserver.cc
pdns/nameserver.hh
pdns/pdns_recursor.cc

index 52f18d595763b81d6299b9e232dd7b74dd54fc99..27b4b81d1130a3dab394fb60d0bc78eb6ebe5df1 100644 (file)
@@ -537,6 +537,7 @@ dumresp_SOURCES = \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dumresp.cc \
+       iputils.cc iputils.hh \
        logger.cc \
        misc.cc misc.hh \
        statbag.cc \
index 610387ca7ae58db57249f8d0667c8d41ec87474c..8bf331ca365e9133935f6c968850ffe70f98426b 100644 (file)
@@ -1839,14 +1839,12 @@ static void setUpLocalBind(std::unique_ptr<ClientState>& cs)
   }
 
   if (cs->reuseport) {
-#ifdef SO_REUSEPORT
-    SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
-    if (warn) {
-      /* no need to warn again if configured but support is not available, we already did for UDP */
-      warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+    if (!setReusePort(fd)) {
+      if (warn) {
+        /* no need to warn again if configured but support is not available, we already did for UDP */
+        warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+      }
     }
-#endif
   }
 
   /* Only set this on IPv4 UDP sockets.
index 5d457dc47f6f0888fb416571ca5eb333967c1b30..96565a025ef539e85f0334d2bbaaebf97639c74a 100644 (file)
@@ -105,12 +105,7 @@ catch(const std::exception& e) {
 static void tcpAcceptor(const ComboAddress local)
 {
   Socket tcpSocket(local.sin4.sin_family, SOCK_STREAM);
-#ifdef SO_REUSEPORT
-  int one=1;
-  if(setsockopt(tcpSocket.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
-    unixDie("setsockopt for REUSEPORT");
-#endif
-
+  setReusePort(tcpSocket.getHandle());
   tcpSocket.bind(local);
   tcpSocket.listen(1024);
 
@@ -187,12 +182,7 @@ try
   }
 
   Socket s(local.sin4.sin_family, SOCK_DGRAM);
-#ifdef SO_REUSEPORT
-  int one=1;
-  if(setsockopt(s.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
-    unixDie("setsockopt for REUSEPORT");
-#endif
-
+  setReusePort(s.getHandle());
   s.bind(local);
   cout<<"Bound to UDP "<<local.toStringWithPort()<<endl;
 
index a13645cbd182c9e07d8da88d56506c66a063a050..624746db80375abc9769d3c0116c438c85380b5e 100644 (file)
@@ -158,6 +158,28 @@ void setSocketIgnorePMTU(int sockfd)
 #endif /* defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) */
 }
 
+bool setReusePort(int sockfd)
+{
+#if defined(SO_REUSEPORT_LB)
+  try {
+    SSetsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT_LB, 1);
+    return true;
+  }
+  catch (const std::exception& e) {
+    return false;
+  }
+#elif defined(SO_REUSEPORT)
+  try {
+    SSetsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, 1);
+    return true;
+  }
+  catch (const std::exception& e) {
+    return false;
+  }
+#endif
+  return false;
+}
+
 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv) 
 {
 #ifdef SO_TIMESTAMP
index 968864100abab752fb406af488c02206d5838b51..48b3748d7fb0688d1386483536886fa8b3566a3d 100644 (file)
@@ -1390,6 +1390,7 @@ int SAccept(int sockfd, ComboAddress& remote);
 int SListen(int sockfd, int limit);
 int SSetsockopt(int sockfd, int level, int opname, int value);
 void setSocketIgnorePMTU(int sockfd);
+bool setReusePort(int sockfd);
 
 #if defined(IP_PKTINFO)
   #define GEN_IP_PKTINFO IP_PKTINFO
index bac4ede45fccae5778034c538158641ef07b4e2e..6d658155a3df88dbd88ca6765199d88d445bc806 100644 (file)
@@ -141,11 +141,11 @@ void UDPNameserver::bindAddresses()
       }
     }
 
-#ifdef SO_REUSEPORT
-    if( d_can_reuseport )
-        if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
-          d_can_reuseport = false;
-#endif
+    if (d_can_reuseport) {
+      if (!setReusePort(s)) {
+        d_can_reuseport = false;
+      }
+    }
 
     if( ::arg().mustDo("non-local-bind") )
       Utility::setBindAny(locala.sin4.sin_family, s);
@@ -208,9 +208,7 @@ bool AddressIsUs(const ComboAddress& remote)
 
 UDPNameserver::UDPNameserver( bool additional_socket )
 {
-#ifdef SO_REUSEPORT
   d_can_reuseport = ::arg().mustDo("reuseport");
-#endif
   // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
   d_additional_socket = additional_socket;
 
index 521d5387517b0303ae71ff467bcaf72a64834bbc..f6e92df644c6659048f8cd83e7951b147cbd7b1c 100644 (file)
@@ -82,18 +82,12 @@ public:
   bool receive(DNSPacket& packet, std::string& buffer); //!< call this in a while or for(;;) loop to get packets
   void send(DNSPacket&); //!< send a DNSPacket. Will call DNSPacket::truncate() if over 512 bytes
   inline bool canReusePort() {
-#ifdef SO_REUSEPORT
     return d_can_reuseport;
-#else
-    return false;
-#endif
   };
   
 private:
   bool d_additional_socket;
-#ifdef SO_REUSEPORT
-  bool d_can_reuseport;
-#endif
+  bool d_can_reuseport{false};
   vector<int> d_sockets;
   void bindAddresses();
   vector<pollfd> d_rfds;
index 29e0c05c6be6ebc43ca4bc391b6a7fb6eca053f2..c2cab50064bcdaed5eac56730f1ee3999390b215 100644 (file)
@@ -2905,12 +2905,23 @@ static void makeTCPServerSockets(deferredAdd_t& deferredAdds, std::set<int>& tcp
     if( ::arg().mustDo("non-local-bind") )
        Utility::setBindAny(AF_INET, fd);
 
-#ifdef SO_REUSEPORT
-    if(g_reusePort) {
-      if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &tmp, sizeof(tmp)) < 0)
-        throw PDNSException("SO_REUSEPORT: "+stringerror());
-    }
+    if (g_reusePort) {
+#if defined(SO_REUSEPORT_LB)
+      try {
+        SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, 1);
+      }
+      catch (const std::exception& e) {
+        throw PDNSException(std::string("SO_REUSEPORT_LB: ") + e.what());
+      }
+#elif defined(SO_REUSEPORT)
+      try {
+        SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1);
+      }
+      catch (const std::exception& e) {
+        throw PDNSException(std::string("SO_REUSEPORT: ") + e.what());
+      }
 #endif
+    }
 
     if (::arg().asNum("tcp-fast-open") > 0) {
 #ifdef TCP_FASTOPEN
@@ -2998,12 +3009,23 @@ static void makeUDPServerSockets(deferredAdd_t& deferredAdds)
     sin.sin4.sin_port = htons(st.port);
 
   
-#ifdef SO_REUSEPORT
-    if(g_reusePort) {
-      if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
-        throw PDNSException("SO_REUSEPORT: "+stringerror());
-    }
+    if (g_reusePort) {
+#if defined(SO_REUSEPORT_LB)
+      try {
+        SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, 1);
+      }
+      catch (const std::exception& e) {
+        throw PDNSException(std::string("SO_REUSEPORT_LB: ") + e.what());
+      }
+#elif defined(SO_REUSEPORT)
+      try {
+        SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1);
+      }
+      catch (const std::exception& e) {
+        throw PDNSException(std::string("SO_REUSEPORT: ") + e.what());
+      }
 #endif
+    }
 
     if (sin.isIPv4()) {
       try {