diff options
Diffstat (limited to 'net/ipv4/udp.c')
| -rw-r--r-- | net/ipv4/udp.c | 97 | 
1 files changed, 41 insertions, 56 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index abfa860367aa..0794a2c46a56 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -407,9 +407,9 @@ static int compute_score(struct sock *sk, struct net *net,  	return score;  } -static u32 udp_ehashfn(const struct net *net, const __be32 laddr, -		       const __u16 lport, const __be32 faddr, -		       const __be16 fport) +INDIRECT_CALLABLE_SCOPE +u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport, +		const __be32 faddr, const __be16 fport)  {  	static u32 udp_ehash_secret __read_mostly; @@ -419,22 +419,6 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,  			      udp_ehash_secret + net_hash_mix(net));  } -static struct sock *lookup_reuseport(struct net *net, struct sock *sk, -				     struct sk_buff *skb, -				     __be32 saddr, __be16 sport, -				     __be32 daddr, unsigned short hnum) -{ -	struct sock *reuse_sk = NULL; -	u32 hash; - -	if (sk->sk_reuseport && sk->sk_state != TCP_ESTABLISHED) { -		hash = udp_ehashfn(net, daddr, hnum, saddr, sport); -		reuse_sk = reuseport_select_sock(sk, hash, skb, -						 sizeof(struct udphdr)); -	} -	return reuse_sk; -} -  /* called with rcu_read_lock() */  static struct sock *udp4_lib_lookup2(struct net *net,  				     __be32 saddr, __be16 sport, @@ -452,42 +436,36 @@ static struct sock *udp4_lib_lookup2(struct net *net,  		score = compute_score(sk, net, saddr, sport,  				      daddr, hnum, dif, sdif);  		if (score > badness) { -			result = lookup_reuseport(net, sk, skb, -						  saddr, sport, daddr, hnum); +			badness = score; + +			if (sk->sk_state == TCP_ESTABLISHED) { +				result = sk; +				continue; +			} + +			result = inet_lookup_reuseport(net, sk, skb, sizeof(struct udphdr), +						       saddr, sport, daddr, hnum, udp_ehashfn); +			if (!result) { +				result = sk; +				continue; +			} +  			/* Fall back to scoring if group has connections */ -			if (result && !reuseport_has_conns(sk)) +			if (!reuseport_has_conns(sk))  				return result; -			result = result ? : sk; -			badness = score; +			/* Reuseport logic returned an error, keep original score. */ +			if (IS_ERR(result)) +				continue; + +			badness = compute_score(result, net, saddr, sport, +						daddr, hnum, dif, sdif); +  		}  	}  	return result;  } -static struct sock *udp4_lookup_run_bpf(struct net *net, -					struct udp_table *udptable, -					struct sk_buff *skb, -					__be32 saddr, __be16 sport, -					__be32 daddr, u16 hnum, const int dif) -{ -	struct sock *sk, *reuse_sk; -	bool no_reuseport; - -	if (udptable != net->ipv4.udp_table) -		return NULL; /* only UDP is supported */ - -	no_reuseport = bpf_sk_lookup_run_v4(net, IPPROTO_UDP, saddr, sport, -					    daddr, hnum, dif, &sk); -	if (no_reuseport || IS_ERR_OR_NULL(sk)) -		return sk; - -	reuse_sk = lookup_reuseport(net, sk, skb, saddr, sport, daddr, hnum); -	if (reuse_sk) -		sk = reuse_sk; -	return sk; -} -  /* UDP is nearly always wildcards out the wazoo, it makes no sense to try   * harder than this. -DaveM   */ @@ -512,9 +490,11 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,  		goto done;  	/* Lookup redirect from BPF */ -	if (static_branch_unlikely(&bpf_sk_lookup_enabled)) { -		sk = udp4_lookup_run_bpf(net, udptable, skb, -					 saddr, sport, daddr, hnum, dif); +	if (static_branch_unlikely(&bpf_sk_lookup_enabled) && +	    udptable == net->ipv4.udp_table) { +		sk = inet_lookup_run_sk_lookup(net, IPPROTO_UDP, skb, sizeof(struct udphdr), +					       saddr, sport, daddr, hnum, dif, +					       udp_ehashfn);  		if (sk) {  			result = sk;  			goto done; @@ -799,7 +779,7 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)  						  (u8 *)(uh+1));  		goto out;  	} -	if (!inet->recverr) { +	if (!inet_test_bit(RECVERR, sk)) {  		if (!harderr || sk->sk_state != TCP_ESTABLISHED)  			goto out;  	} else @@ -982,7 +962,8 @@ csum_partial:  send:  	err = ip_send_skb(sock_net(sk), skb);  	if (err) { -		if (err == -ENOBUFS && !inet->recverr) { +		if (err == -ENOBUFS && +		    !inet_test_bit(RECVERR, sk)) {  			UDP_INC_STATS(sock_net(sk),  				      UDP_MIB_SNDBUFERRORS, is_udplite);  			err = 0; @@ -1557,7 +1538,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)  	spin_unlock(&list->lock);  	if (!sock_flag(sk, SOCK_DEAD)) -		sk->sk_data_ready(sk); +		INDIRECT_CALL_1(sk->sk_data_ready, sock_def_readable, sk);  	busylock_release(busy);  	return 0; @@ -1890,7 +1871,7 @@ try_again:  	if (udp_sk(sk)->gro_enabled)  		udp_cmsg_recv(msg, sk, skb); -	if (inet->cmsg_flags) +	if (inet_cmsg_flags(inet))  		ip_cmsg_recv_offset(msg, sk, skb, sizeof(struct udphdr), off);  	err = copied; @@ -2412,7 +2393,11 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,  	if (udp4_csum_init(skb, uh, proto))  		goto csum_error; -	sk = skb_steal_sock(skb, &refcounted); +	sk = inet_steal_sock(net, skb, sizeof(struct udphdr), saddr, uh->source, daddr, uh->dest, +			     &refcounted, udp_ehashfn); +	if (IS_ERR(sk)) +		goto no_sk; +  	if (sk) {  		struct dst_entry *dst = skb_dst(skb);  		int ret; @@ -2433,7 +2418,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,  	sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);  	if (sk)  		return udp_unicast_rcv_skb(sk, skb, uh); - +no_sk:  	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))  		goto drop;  	nf_reset_ct(skb);  | 
