]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
more changes
authorMark Zealey <mark@markandruth.co.uk>
Mon, 9 Dec 2013 12:01:02 +0000 (14:01 +0200)
committerMark Zealey <mark@markandruth.co.uk>
Mon, 9 Dec 2013 12:01:02 +0000 (14:01 +0200)
pdns/common_startup.cc
pdns/docs/pdns.xml
pdns/nameserver.cc
pdns/nameserver.hh

index af0bd6b521549f9db64dd46fb3c891bad1248f93..2294ce6051dacc64b8dce79e894bd55a4880bb0b 100644 (file)
@@ -54,6 +54,7 @@ void declareArguments()
   ::arg().set("smtpredirector","Our smtpredir MX host")="a.misconfigured.powerdns.smtp.server";
   ::arg().set("local-address","Local IP addresses to which we bind")="0.0.0.0";
   ::arg().set("local-ipv6","Local IP address to which we bind")="";
+  ::arg().setSwitch("reuseport","Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket")="";
   ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
   ::arg().set("query-local-address6","Source IPv6 address for sending queries")="::";
   ::arg().set("overload-queue-length","Maximum queuelength moving to packetcache only")="0";
@@ -247,8 +248,10 @@ void *qthread(void *number)
 
   // If we have SO_REUSEPORT then create a new port for all receiver threads
   // other than the first one.
-  if( number > 0 && NS->canReusePort() )
-    NS = new UDPNameserver();
+  if( number > 0 && NS->canReusePort() ) {
+    L<<Logger::Notice<<"Starting new listen thread on the same IPs/ports using SO_REUSEPORT"<<endl;
+    NS = new UDPNameserver( true );
+  }
 
   for(;;) {
     if (skipfirst)
index 9f9bda4468278b95eb377fee0c85e54e5ad4fc72..27a2179be97bdef5abc2d9950173e133fe50f5db 100644 (file)
@@ -16180,6 +16180,18 @@ Tell PowerDNS to log all incoming DNS queries. This will lead to a lot of loggin
            <listitem><para>
              If this many packets are waiting for database attention, answer any new questions strictly from the packet cache.
              </para></listitem></varlistentry>
+         <varlistentry><term>reuseport=[yes|no]</term>
+           <listitem><para>
+          On Linux 3.9 and some BSD kernels the SO_REUSEPORT option allows each
+          receiver-thread to open a new socket on the same port which allows
+          for much higher performance on multi-core boxes. Setting this option
+          will enable use of SO_REUSEPORT when available and seamlessly fall
+          back to a single socket when it is not available. A side-effect is
+          that you can start multiple servers on the same IP/port combination
+          which may or may not be a good idea. You could use this to enable
+          transparent restarts, but it may also mask configuration issues and
+          for this reason it is disabled by default.
+             </para></listitem></varlistentry>
          <varlistentry>
            <term>server-id</term>
            <listitem>
index 5b99520a1a5620ccc29560137cf218a39126e0ba..75ab1d511c900de87082126562264966edfeba08 100644 (file)
@@ -89,7 +89,6 @@ extern StatBag S;
 #endif
 
 vector<ComboAddress> g_localaddresses; // not static, our unit tests need to poke this
-pthread_mutex_t localaddresses_lock=PTHREAD_MUTEX_INITIALIZER;
 
 void UDPNameserver::bindIPv4()
 {
@@ -124,17 +123,17 @@ void UDPNameserver::bindIPv4()
       setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
 
 #ifdef SO_REUSEPORT
-    if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
-      d_can_reuseport = false;
+    if( d_can_reuseport )
+        if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
+          d_can_reuseport = false;
 #endif
 
     locala=ComboAddress(localname, ::arg().asNum("local-port"));
     if(locala.sin4.sin_family != AF_INET) 
       throw PDNSException("Attempting to bind IPv4 socket to IPv6 address");
 
-    pthread_mutex_lock(&localaddresses_lock);
-    g_localaddresses.push_back(locala);
-    pthread_mutex_unlock(&localaddresses_lock);
+    if( !d_additional_socket )
+        g_localaddresses.push_back(locala);
 
     if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
       L<<Logger::Error<<"binding UDP socket to '"+locala.toStringWithPort()+": "<<strerror(errno)<<endl;
@@ -228,11 +227,13 @@ void UDPNameserver::bindIPv6()
     }
 
 #ifdef SO_REUSEPORT
-    if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
-      d_can_reuseport = false;
+    if( d_can_reuseport )
+        if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
+          d_can_reuseport = false;
 #endif
 
-    g_localaddresses.push_back(locala);
+    if( !d_additional_socket )
+        g_localaddresses.push_back(locala);
     if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
       L<<Logger::Error<<"binding to UDP ipv6 socket: "<<strerror(errno)<<endl;
       throw PDNSException("Unable to bind to UDP ipv6 socket");
@@ -249,11 +250,13 @@ void UDPNameserver::bindIPv6()
 #endif
 }
 
-UDPNameserver::UDPNameserver()
+UDPNameserver::UDPNameserver( bool additional_socket )
 {
 #ifdef SO_REUSEPORT
-  d_can_reuseport = true;
+  d_can_reuseport = ::arg().mustDo("reuseport");
 #endif
+  // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
+  d_additional_socket = additional_socket;
 
   if(!::arg()["local-address"].empty())
     bindIPv4();
index 642d8193450e25766ee1025bbd475f3f407567ec..d33628296f8428fe9850b17ebe0e78890aeb3396 100644 (file)
@@ -80,7 +80,7 @@
 class UDPNameserver
 {
 public:
-  UDPNameserver();  //!< Opens the socket
+  UDPNameserver( bool additional_socket = false );  //!< Opens the socket
   DNSPacket *receive(DNSPacket *prefilled=0); //!< 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() {
@@ -92,6 +92,7 @@ public:
   };
   
 private:
+  bool d_additional_socket;
 #ifdef SO_REUSEPORT
   bool d_can_reuseport;
 #endif