|
@@ -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 @@ begin:
|
|
|
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 @@ begin:
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
/*
|