mirror of https://gitee.com/openkylin/linux.git
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: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5ba24953e9
commit
72289b96c9
|
@ -45,6 +45,7 @@
|
|||
#include <net/tcp_states.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/inet6_hashtables.h>
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
|
|||
{
|
||||
struct sock *sk, *result;
|
||||
struct hlist_nulls_node *node;
|
||||
int score, badness;
|
||||
int score, badness, matches = 0, reuseport = 0;
|
||||
u32 hash = 0;
|
||||
|
||||
begin:
|
||||
result = NULL;
|
||||
|
@ -214,8 +216,18 @@ static struct sock *udp6_lib_lookup2(struct net *net,
|
|||
if (score > badness) {
|
||||
result = sk;
|
||||
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;
|
||||
} 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,
|
|||
unsigned short hnum = ntohs(dport);
|
||||
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
|
||||
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
|
||||
int score, badness;
|
||||
int score, badness, matches = 0, reuseport = 0;
|
||||
u32 hash = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
if (hslot->count > 10) {
|
||||
|
@ -284,6 +297,17 @@ struct sock *__udp6_lib_lookup(struct net *net,
|
|||
if (score > badness) {
|
||||
result = sk;
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue