Skip to content

Commit

Permalink
Add support for FreeBSD's SO_REUSEPORT_LB
Browse files Browse the repository at this point in the history
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".
  • Loading branch information
rgacogne committed May 26, 2020
1 parent a028959 commit 665821e
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 43 deletions.
1 change: 1 addition & 0 deletions pdns/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
12 changes: 5 additions & 7 deletions pdns/dnsdist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 2 additions & 12 deletions pdns/dumresp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
22 changes: 22 additions & 0 deletions pdns/iputils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions pdns/iputils.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 5 additions & 7 deletions pdns/nameserver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down
8 changes: 1 addition & 7 deletions pdns/nameserver.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
42 changes: 32 additions & 10 deletions pdns/pdns_recursor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 665821e

Please sign in to comment.