|
@@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
|
|
|
return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr);
|
|
|
}
|
|
|
|
|
|
-static inline int compute_score(struct sock *sk, struct net *net,
|
|
|
- __be32 saddr, unsigned short hnum, __be16 sport,
|
|
|
- __be32 daddr, __be16 dport, int dif)
|
|
|
+static int compute_score(struct sock *sk, struct net *net,
|
|
|
+ __be32 saddr, __be16 sport,
|
|
|
+ __be32 daddr, unsigned short hnum, int dif)
|
|
|
{
|
|
|
int score;
|
|
|
struct inet_sock *inet;
|
|
@@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
|
|
return score;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
|
|
|
- */
|
|
|
-static inline int compute_score2(struct sock *sk, struct net *net,
|
|
|
- __be32 saddr, __be16 sport,
|
|
|
- __be32 daddr, unsigned int hnum, int dif)
|
|
|
-{
|
|
|
- int score;
|
|
|
- struct inet_sock *inet;
|
|
|
-
|
|
|
- if (!net_eq(sock_net(sk), net) ||
|
|
|
- ipv6_only_sock(sk))
|
|
|
- return -1;
|
|
|
-
|
|
|
- inet = inet_sk(sk);
|
|
|
-
|
|
|
- if (inet->inet_rcv_saddr != daddr ||
|
|
|
- inet->inet_num != hnum)
|
|
|
- return -1;
|
|
|
-
|
|
|
- score = (sk->sk_family == PF_INET) ? 2 : 1;
|
|
|
-
|
|
|
- if (inet->inet_daddr) {
|
|
|
- if (inet->inet_daddr != saddr)
|
|
|
- return -1;
|
|
|
- score += 4;
|
|
|
- }
|
|
|
-
|
|
|
- if (inet->inet_dport) {
|
|
|
- if (inet->inet_dport != sport)
|
|
|
- return -1;
|
|
|
- score += 4;
|
|
|
- }
|
|
|
-
|
|
|
- if (sk->sk_bound_dev_if) {
|
|
|
- if (sk->sk_bound_dev_if != dif)
|
|
|
- return -1;
|
|
|
- score += 4;
|
|
|
- }
|
|
|
-
|
|
|
- if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
|
|
- score++;
|
|
|
-
|
|
|
- return score;
|
|
|
-}
|
|
|
-
|
|
|
static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
|
|
|
const __u16 lport, const __be32 faddr,
|
|
|
const __be16 fport)
|
|
@@ -492,11 +446,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
|
|
|
udp_ehash_secret + net_hash_mix(net));
|
|
|
}
|
|
|
|
|
|
-/* called with read_rcu_lock() */
|
|
|
+/* called with rcu_read_lock() */
|
|
|
static struct sock *udp4_lib_lookup2(struct net *net,
|
|
|
__be32 saddr, __be16 sport,
|
|
|
__be32 daddr, unsigned int hnum, int dif,
|
|
|
- struct udp_hslot *hslot2, unsigned int slot2,
|
|
|
+ struct udp_hslot *hslot2,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
|
struct sock *sk, *result;
|
|
@@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
|
|
|
result = NULL;
|
|
|
badness = 0;
|
|
|
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
|
|
|
- score = compute_score2(sk, net, saddr, sport,
|
|
|
+ score = compute_score(sk, net, saddr, sport,
|
|
|
daddr, hnum, dif);
|
|
|
if (score > badness) {
|
|
|
reuseport = sk->sk_reuseport;
|
|
@@ -554,17 +508,22 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
|
|
|
|
|
|
result = udp4_lib_lookup2(net, saddr, sport,
|
|
|
daddr, hnum, dif,
|
|
|
- hslot2, slot2, skb);
|
|
|
+ hslot2, skb);
|
|
|
if (!result) {
|
|
|
+ unsigned int old_slot2 = slot2;
|
|
|
hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
|
|
|
slot2 = hash2 & udptable->mask;
|
|
|
+ /* avoid searching the same slot again. */
|
|
|
+ if (unlikely(slot2 == old_slot2))
|
|
|
+ return result;
|
|
|
+
|
|
|
hslot2 = &udptable->hash2[slot2];
|
|
|
if (hslot->count < hslot2->count)
|
|
|
goto begin;
|
|
|
|
|
|
result = udp4_lib_lookup2(net, saddr, sport,
|
|
|
- htonl(INADDR_ANY), hnum, dif,
|
|
|
- hslot2, slot2, skb);
|
|
|
+ daddr, hnum, dif,
|
|
|
+ hslot2, skb);
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
@@ -572,8 +531,8 @@ begin:
|
|
|
result = NULL;
|
|
|
badness = 0;
|
|
|
sk_for_each_rcu(sk, &hslot->head) {
|
|
|
- score = compute_score(sk, net, saddr, hnum, sport,
|
|
|
- daddr, dport, dif);
|
|
|
+ score = compute_score(sk, net, saddr, sport,
|
|
|
+ daddr, hnum, dif);
|
|
|
if (score > badness) {
|
|
|
reuseport = sk->sk_reuseport;
|
|
|
if (reuseport) {
|