diff options
Diffstat (limited to 'net/ipv6/udp.c')
| -rw-r--r-- | net/ipv6/udp.c | 70 | 
1 files changed, 30 insertions, 40 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index dfaa29b8b293..599e1ba6d1ce 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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);  		}  	}  	/* @@ -443,7 +467,7 @@ try_again:  			ip_cmsg_recv(msg, skb);  	} else {  		if (np->rxopt.all) -			datagram_recv_ctl(sk, msg, skb); +			ip6_datagram_recv_ctl(sk, msg, skb);  	}  	err = copied; @@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,  	return 0;  } -static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, -				 int proto) -{ -	int err; - -	UDP_SKB_CB(skb)->partial_cov = 0; -	UDP_SKB_CB(skb)->cscov = skb->len; - -	if (proto == IPPROTO_UDPLITE) { -		err = udplite_checksum_init(skb, uh); -		if (err) -			return err; -	} - -	if (uh->check == 0) { -		/* RFC 2460 section 8.1 says that we SHOULD log -		   this error. Well, it is reasonable. -		 */ -		LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); -		return 1; -	} -	if (skb->ip_summed == CHECKSUM_COMPLETE && -	    !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, -			     skb->len, proto, skb->csum)) -		skb->ip_summed = CHECKSUM_UNNECESSARY; - -	if (!skb_csum_unnecessary(skb)) -		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -							 &ipv6_hdr(skb)->daddr, -							 skb->len, proto, 0)); - -	return 0; -} -  int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,  		   int proto)  { @@ -1153,8 +1143,8 @@ do_udp_sendmsg:  		memset(opt, 0, sizeof(struct ipv6_txoptions));  		opt->tot_len = sizeof(*opt); -		err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, -					&hlimit, &tclass, &dontfrag); +		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, +					    &hlimit, &tclass, &dontfrag);  		if (err < 0) {  			fl6_sock_release(flowlabel);  			return err;  |