diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 80 |
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 | ||
394 | static inline int compute_score(struct sock *sk, struct net *net, | 394 | static 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 | */ | ||
440 | static 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 | |||
483 | static u32 udp_ehashfn(const struct net *net, const __be32 laddr, | 437 | static 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() */ |
496 | static struct sock *udp4_lib_lookup2(struct net *net, | 450 | static 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 | /* |