Commit 72289b96 authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller
Browse files

soreuseport: UDP/IPv6 implementation



Motivation for soreuseport would be something like a DNS server.  An
alternative would be to recv on the same socket from multiple threads.
As in the case of TCP, the load across these threads tends to be
disproportionate and we also see a lot of contection on the socket lock.
Note that SO_REUSEADDR already allows multiple UDP sockets to bind to
the same port, however there is no provision to prevent hijacking and
nothing to distribute packets across all the sockets sharing the same
bound port.  This patch does not change the semantics of SO_REUSEADDR,
but provides usable functionality of it for unicast.
Signed-off-by: default avatarTom Herbert <therbert@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5ba24953
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <net/tcp_states.h> #include <net/tcp_states.h>
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/inet6_hashtables.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net, ...@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
{ {
struct sock *sk, *result; struct sock *sk, *result;
struct hlist_nulls_node *node; struct hlist_nulls_node *node;
int score, badness; int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
begin: begin:
result = NULL; result = NULL;
...@@ -214,8 +216,18 @@ begin: ...@@ -214,8 +216,18 @@ begin:
if (score > badness) { if (score > badness) {
result = sk; result = sk;
badness = score; badness = score;
if (score == SCORE2_MAX) reuseport = sk->sk_reuseport;
if (reuseport) {
hash = inet6_ehashfn(net, daddr, hnum,
saddr, sport);
matches = 1;
} else if (score == SCORE2_MAX)
goto exact_match; goto exact_match;
} else if (score == badness && reuseport) {
matches++;
if (((u64)hash * matches) >> 32 == 0)
result = sk;
hash = next_pseudo_random32(hash);
} }
} }
/* /*
...@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net, ...@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
unsigned short hnum = ntohs(dport); unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
int score, badness; int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
rcu_read_lock(); rcu_read_lock();
if (hslot->count > 10) { if (hslot->count > 10) {
...@@ -284,6 +297,17 @@ begin: ...@@ -284,6 +297,17 @@ begin:
if (score > badness) { if (score > badness) {
result = sk; result = sk;
badness = score; badness = score;
reuseport = sk->sk_reuseport;
if (reuseport) {
hash = inet6_ehashfn(net, daddr, hnum,
saddr, sport);
matches = 1;
}
} else if (score == badness && reuseport) {
matches++;
if (((u64)hash * matches) >> 32 == 0)
result = sk;
hash = next_pseudo_random32(hash);
} }
} }
/* /*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment