aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r--net/ipv4/udp.c80
1 files changed, 21 insertions, 59 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0ff31d97d485..ca5e8ea29538 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
391 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); 391 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr);
392} 392}
393 393
394static inline int compute_score(struct sock *sk, struct net *net, 394static int compute_score(struct sock *sk, struct net *net,
395 __be32 saddr, unsigned short hnum, __be16 sport, 395 __be32 saddr, __be16 sport,
396 __be32 daddr, __be16 dport, int dif) 396 __be32 daddr, unsigned short hnum, int dif)
397{ 397{
398 int score; 398 int score;
399 struct inet_sock *inet; 399 struct inet_sock *inet;
@@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct net *net,
434 return score; 434 return score;
435} 435}
436 436
437/*
438 * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
439 */
440static inline int compute_score2(struct sock *sk, struct net *net,
441 __be32 saddr, __be16 sport,
442 __be32 daddr, unsigned int hnum, int dif)
443{
444 int score;
445 struct inet_sock *inet;
446
447 if (!net_eq(sock_net(sk), net) ||
448 ipv6_only_sock(sk))
449 return -1;
450
451 inet = inet_sk(sk);
452
453 if (inet->inet_rcv_saddr != daddr ||
454 inet->inet_num != hnum)
455 return -1;
456
457 score = (sk->sk_family == PF_INET) ? 2 : 1;
458
459 if (inet->inet_daddr) {
460 if (inet->inet_daddr != saddr)
461 return -1;
462 score += 4;
463 }
464
465 if (inet->inet_dport) {
466 if (inet->inet_dport != sport)
467 return -1;
468 score += 4;
469 }
470
471 if (sk->sk_bound_dev_if) {
472 if (sk->sk_bound_dev_if != dif)
473 return -1;
474 score += 4;
475 }
476
477 if (sk->sk_incoming_cpu == raw_smp_processor_id())
478 score++;
479
480 return score;
481}
482
483static u32 udp_ehashfn(const struct net *net, const __be32 laddr, 437static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
484 const __u16 lport, const __be32 faddr, 438 const __u16 lport, const __be32 faddr,
485 const __be16 fport) 439 const __be16 fport)
@@ -492,11 +446,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
492 udp_ehash_secret + net_hash_mix(net)); 446 udp_ehash_secret + net_hash_mix(net));
493} 447}
494 448
495/* called with read_rcu_lock() */ 449/* called with rcu_read_lock() */
496static struct sock *udp4_lib_lookup2(struct net *net, 450static struct sock *udp4_lib_lookup2(struct net *net,
497 __be32 saddr, __be16 sport, 451 __be32 saddr, __be16 sport,
498 __be32 daddr, unsigned int hnum, int dif, 452 __be32 daddr, unsigned int hnum, int dif,
499 struct udp_hslot *hslot2, unsigned int slot2, 453 struct udp_hslot *hslot2,
500 struct sk_buff *skb) 454 struct sk_buff *skb)
501{ 455{
502 struct sock *sk, *result; 456 struct sock *sk, *result;
@@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
506 result = NULL; 460 result = NULL;
507 badness = 0; 461 badness = 0;
508 udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { 462 udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
509 score = compute_score2(sk, net, saddr, sport, 463 score = compute_score(sk, net, saddr, sport,
510 daddr, hnum, dif); 464 daddr, hnum, dif);
511 if (score > badness) { 465 if (score > badness) {
512 reuseport = sk->sk_reuseport; 466 reuseport = sk->sk_reuseport;
@@ -554,17 +508,22 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
554 508
555 result = udp4_lib_lookup2(net, saddr, sport, 509 result = udp4_lib_lookup2(net, saddr, sport,
556 daddr, hnum, dif, 510 daddr, hnum, dif,
557 hslot2, slot2, skb); 511 hslot2, skb);
558 if (!result) { 512 if (!result) {
513 unsigned int old_slot2 = slot2;
559 hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); 514 hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
560 slot2 = hash2 & udptable->mask; 515 slot2 = hash2 & udptable->mask;
516 /* avoid searching the same slot again. */
517 if (unlikely(slot2 == old_slot2))
518 return result;
519
561 hslot2 = &udptable->hash2[slot2]; 520 hslot2 = &udptable->hash2[slot2];
562 if (hslot->count < hslot2->count) 521 if (hslot->count < hslot2->count)
563 goto begin; 522 goto begin;
564 523
565 result = udp4_lib_lookup2(net, saddr, sport, 524 result = udp4_lib_lookup2(net, saddr, sport,
566 htonl(INADDR_ANY), hnum, dif, 525 daddr, hnum, dif,
567 hslot2, slot2, skb); 526 hslot2, skb);
568 } 527 }
569 return result; 528 return result;
570 } 529 }
@@ -572,8 +531,8 @@ begin:
572 result = NULL; 531 result = NULL;
573 badness = 0; 532 badness = 0;
574 sk_for_each_rcu(sk, &hslot->head) { 533 sk_for_each_rcu(sk, &hslot->head) {
575 score = compute_score(sk, net, saddr, hnum, sport, 534 score = compute_score(sk, net, saddr, sport,
576 daddr, dport, dif); 535 daddr, hnum, dif);
577 if (score > badness) { 536 if (score > badness) {
578 reuseport = sk->sk_reuseport; 537 reuseport = sk->sk_reuseport;
579 if (reuseport) { 538 if (reuseport) {
@@ -1755,8 +1714,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
1755 return err; 1714 return err;
1756 } 1715 }
1757 1716
1758 return skb_checksum_init_zero_check(skb, proto, uh->check, 1717 /* Note, we are only interested in != 0 or == 0, thus the
1759 inet_compute_pseudo); 1718 * force to int.
1719 */
1720 return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check,
1721 inet_compute_pseudo);
1760} 1722}
1761 1723
1762/* 1724/*