mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	inet: move inet->transparent to inet->inet_flags
IP_TRANSPARENT socket option can now be set/read
without locking the socket.
v2: removed unused issk variable in mptcp_setsockopt_sol_ip_set_transparent()
v4: rebased after commit 3f326a821b ("mptcp: change the mpc check helper to return a sk")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									307b4ac6dc
								
							
						
					
					
						commit
						4bd0623f04
					
				
					 11 changed files with 30 additions and 34 deletions
				
			
		| 
						 | 
					@ -231,7 +231,6 @@ struct inet_sock {
 | 
				
			||||||
	__u8			mc_ttl;
 | 
						__u8			mc_ttl;
 | 
				
			||||||
	__u8			pmtudisc;
 | 
						__u8			pmtudisc;
 | 
				
			||||||
	__u8			is_icsk:1,
 | 
						__u8			is_icsk:1,
 | 
				
			||||||
				transparent:1,
 | 
					 | 
				
			||||||
				nodefrag:1;
 | 
									nodefrag:1;
 | 
				
			||||||
	__u8			bind_address_no_port:1,
 | 
						__u8			bind_address_no_port:1,
 | 
				
			||||||
				defer_connect:1; /* Indicates that fastopen_connect is set
 | 
									defer_connect:1; /* Indicates that fastopen_connect is set
 | 
				
			||||||
| 
						 | 
					@ -271,6 +270,7 @@ enum {
 | 
				
			||||||
	INET_FLAGS_HDRINCL	= 12,
 | 
						INET_FLAGS_HDRINCL	= 12,
 | 
				
			||||||
	INET_FLAGS_MC_LOOP	= 13,
 | 
						INET_FLAGS_MC_LOOP	= 13,
 | 
				
			||||||
	INET_FLAGS_MC_ALL	= 14,
 | 
						INET_FLAGS_MC_ALL	= 14,
 | 
				
			||||||
 | 
						INET_FLAGS_TRANSPARENT	= 15,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* cmsg flags for inet */
 | 
					/* cmsg flags for inet */
 | 
				
			||||||
| 
						 | 
					@ -397,7 +397,7 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__u8 flags = 0;
 | 
						__u8 flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (inet_sk(sk)->transparent || inet_test_bit(HDRINCL, sk))
 | 
						if (inet_test_bit(TRANSPARENT, sk) || inet_test_bit(HDRINCL, sk))
 | 
				
			||||||
		flags |= FLOWI_FLAG_ANYSRC;
 | 
							flags |= FLOWI_FLAG_ANYSRC;
 | 
				
			||||||
	return flags;
 | 
						return flags;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -424,7 +424,7 @@ static inline bool inet_can_nonlocal_bind(struct net *net,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) ||
 | 
						return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) ||
 | 
				
			||||||
		test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) ||
 | 
							test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) ||
 | 
				
			||||||
		inet->transparent;
 | 
							test_bit(INET_FLAGS_TRANSPARENT, &inet->inet_flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool inet_addr_valid_or_nonlocal(struct net *net,
 | 
					static inline bool inet_addr_valid_or_nonlocal(struct net *net,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -938,7 +938,7 @@ static inline bool ipv6_can_nonlocal_bind(struct net *net,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return net->ipv6.sysctl.ip_nonlocal_bind ||
 | 
						return net->ipv6.sysctl.ip_nonlocal_bind ||
 | 
				
			||||||
		test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) ||
 | 
							test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) ||
 | 
				
			||||||
		inet->transparent;
 | 
							test_bit(INET_FLAGS_TRANSPARENT, &inet->inet_flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Sysctl settings for net ipv6.auto_flowlabels */
 | 
					/* Sysctl settings for net ipv6.auto_flowlabels */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,7 +298,7 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__u8 flow_flags = 0;
 | 
						__u8 flow_flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (inet_sk(sk)->transparent)
 | 
						if (inet_test_bit(TRANSPARENT, sk))
 | 
				
			||||||
		flow_flags |= FLOWI_FLAG_ANYSRC;
 | 
							flow_flags |= FLOWI_FLAG_ANYSRC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flowi4_init_output(fl4, oif, READ_ONCE(sk->sk_mark), ip_sock_rt_tos(sk),
 | 
						flowi4_init_output(fl4, oif, READ_ONCE(sk->sk_mark), ip_sock_rt_tos(sk),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2031,7 +2031,7 @@ static inline bool inet_sk_transparent(const struct sock *sk)
 | 
				
			||||||
	case TCP_NEW_SYN_RECV:
 | 
						case TCP_NEW_SYN_RECV:
 | 
				
			||||||
		return inet_rsk(inet_reqsk(sk))->no_srccheck;
 | 
							return inet_rsk(inet_reqsk(sk))->no_srccheck;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return inet_sk(sk)->transparent;
 | 
						return inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Determines whether this is a thin stream (which may suffer from
 | 
					/* Determines whether this is a thin stream (which may suffer from
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
	inet_sockopt.freebind	= inet_test_bit(FREEBIND, sk);
 | 
						inet_sockopt.freebind	= inet_test_bit(FREEBIND, sk);
 | 
				
			||||||
	inet_sockopt.hdrincl	= inet_test_bit(HDRINCL, sk);
 | 
						inet_sockopt.hdrincl	= inet_test_bit(HDRINCL, sk);
 | 
				
			||||||
	inet_sockopt.mc_loop	= inet_test_bit(MC_LOOP, sk);
 | 
						inet_sockopt.mc_loop	= inet_test_bit(MC_LOOP, sk);
 | 
				
			||||||
	inet_sockopt.transparent = inet->transparent;
 | 
						inet_sockopt.transparent = inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
	inet_sockopt.mc_all	= inet_test_bit(MC_ALL, sk);
 | 
						inet_sockopt.mc_all	= inet_test_bit(MC_ALL, sk);
 | 
				
			||||||
	inet_sockopt.nodefrag	= inet->nodefrag;
 | 
						inet_sockopt.nodefrag	= inet->nodefrag;
 | 
				
			||||||
	inet_sockopt.bind_address_no_port = inet->bind_address_no_port;
 | 
						inet_sockopt.bind_address_no_port = inet->bind_address_no_port;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,7 +203,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
 | 
				
			||||||
		tw->tw_reuseport    = sk->sk_reuseport;
 | 
							tw->tw_reuseport    = sk->sk_reuseport;
 | 
				
			||||||
		tw->tw_hash	    = sk->sk_hash;
 | 
							tw->tw_hash	    = sk->sk_hash;
 | 
				
			||||||
		tw->tw_ipv6only	    = 0;
 | 
							tw->tw_ipv6only	    = 0;
 | 
				
			||||||
		tw->tw_transparent  = inet->transparent;
 | 
							tw->tw_transparent  = inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
		tw->tw_prot	    = sk->sk_prot_creator;
 | 
							tw->tw_prot	    = sk->sk_prot_creator;
 | 
				
			||||||
		atomic64_set(&tw->tw_cookie, atomic64_read(&sk->sk_cookie));
 | 
							atomic64_set(&tw->tw_cookie, atomic64_read(&sk->sk_cookie));
 | 
				
			||||||
		twsk_net_set(tw, sock_net(sk));
 | 
							twsk_net_set(tw, sock_net(sk));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1005,7 +1005,16 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		inet_assign_bit(MC_ALL, sk, val);
 | 
							inet_assign_bit(MC_ALL, sk, val);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
						case IP_TRANSPARENT:
 | 
				
			||||||
 | 
							if (!!val && !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
 | 
				
			||||||
 | 
							    !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
 | 
				
			||||||
 | 
								err = -EPERM;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (optlen < 1)
 | 
				
			||||||
 | 
								goto e_inval;
 | 
				
			||||||
 | 
							inet_assign_bit(TRANSPARENT, sk, val);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = 0;
 | 
						err = 0;
 | 
				
			||||||
| 
						 | 
					@ -1319,17 +1328,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
		err = xfrm_user_policy(sk, optname, optval, optlen);
 | 
							err = xfrm_user_policy(sk, optname, optval, optlen);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IP_TRANSPARENT:
 | 
					 | 
				
			||||||
		if (!!val && !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
 | 
					 | 
				
			||||||
		    !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
 | 
					 | 
				
			||||||
			err = -EPERM;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (optlen < 1)
 | 
					 | 
				
			||||||
			goto e_inval;
 | 
					 | 
				
			||||||
		inet->transparent = !!val;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case IP_MINTTL:
 | 
						case IP_MINTTL:
 | 
				
			||||||
		if (optlen < 1)
 | 
							if (optlen < 1)
 | 
				
			||||||
			goto e_inval;
 | 
								goto e_inval;
 | 
				
			||||||
| 
						 | 
					@ -1585,6 +1583,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
	case IP_MULTICAST_ALL:
 | 
						case IP_MULTICAST_ALL:
 | 
				
			||||||
		val = inet_test_bit(MC_ALL, sk);
 | 
							val = inet_test_bit(MC_ALL, sk);
 | 
				
			||||||
		goto copyval;
 | 
							goto copyval;
 | 
				
			||||||
 | 
						case IP_TRANSPARENT:
 | 
				
			||||||
 | 
							val = inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
 | 
							goto copyval;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (needs_rtnl)
 | 
						if (needs_rtnl)
 | 
				
			||||||
| 
						 | 
					@ -1735,9 +1736,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
		len -= msg.msg_controllen;
 | 
							len -= msg.msg_controllen;
 | 
				
			||||||
		return copy_to_sockptr(optlen, &len, sizeof(int));
 | 
							return copy_to_sockptr(optlen, &len, sizeof(int));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	case IP_TRANSPARENT:
 | 
					 | 
				
			||||||
		val = inet->transparent;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case IP_MINTTL:
 | 
						case IP_MINTTL:
 | 
				
			||||||
		val = inet->min_ttl;
 | 
							val = inet->min_ttl;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7000,7 +7000,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 | 
						tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 | 
				
			||||||
	tcp_openreq_init(req, &tmp_opt, skb, sk);
 | 
						tcp_openreq_init(req, &tmp_opt, skb, sk);
 | 
				
			||||||
	inet_rsk(req)->no_srccheck = inet_sk(sk)->transparent;
 | 
						inet_rsk(req)->no_srccheck = inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 | 
						/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 | 
				
			||||||
	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 | 
						inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,9 +289,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 | 
				
			||||||
	if (tw) {
 | 
						if (tw) {
 | 
				
			||||||
		struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
 | 
							struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
 | 
				
			||||||
		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
 | 
							const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
 | 
				
			||||||
		struct inet_sock *inet = inet_sk(sk);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tw->tw_transparent	= inet->transparent;
 | 
							tw->tw_transparent	= inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
		tw->tw_mark		= sk->sk_mark;
 | 
							tw->tw_mark		= sk->sk_mark;
 | 
				
			||||||
		tw->tw_priority		= sk->sk_priority;
 | 
							tw->tw_priority		= sk->sk_priority;
 | 
				
			||||||
		tw->tw_rcv_wscale	= tp->rx_opt.rcv_wscale;
 | 
							tw->tw_rcv_wscale	= tp->rx_opt.rcv_wscale;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -633,7 +633,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
		if (optlen < sizeof(int))
 | 
							if (optlen < sizeof(int))
 | 
				
			||||||
			goto e_inval;
 | 
								goto e_inval;
 | 
				
			||||||
		/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
 | 
							/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
 | 
				
			||||||
		inet_sk(sk)->transparent = valbool;
 | 
							inet_assign_bit(TRANSPARENT, sk, valbool);
 | 
				
			||||||
		retv = 0;
 | 
							retv = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1330,7 +1330,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPV6_TRANSPARENT:
 | 
						case IPV6_TRANSPARENT:
 | 
				
			||||||
		val = inet_sk(sk)->transparent;
 | 
							val = inet_test_bit(TRANSPARENT, sk);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPV6_FREEBIND:
 | 
						case IPV6_FREEBIND:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -416,7 +416,8 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
 | 
				
			||||||
			sk->sk_ipv6only = ssk->sk_ipv6only;
 | 
								sk->sk_ipv6only = ssk->sk_ipv6only;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case IPV6_TRANSPARENT:
 | 
							case IPV6_TRANSPARENT:
 | 
				
			||||||
			inet_sk(sk)->transparent = inet_sk(ssk)->transparent;
 | 
								inet_assign_bit(TRANSPARENT, sk,
 | 
				
			||||||
 | 
										inet_test_bit(TRANSPARENT, ssk));
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case IPV6_FREEBIND:
 | 
							case IPV6_FREEBIND:
 | 
				
			||||||
			inet_assign_bit(FREEBIND, sk,
 | 
								inet_assign_bit(FREEBIND, sk,
 | 
				
			||||||
| 
						 | 
					@ -685,7 +686,6 @@ static int mptcp_setsockopt_sol_ip_set_transparent(struct mptcp_sock *msk, int o
 | 
				
			||||||
						   sockptr_t optval, unsigned int optlen)
 | 
											   sockptr_t optval, unsigned int optlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sock *sk = (struct sock *)msk;
 | 
						struct sock *sk = (struct sock *)msk;
 | 
				
			||||||
	struct inet_sock *issk;
 | 
					 | 
				
			||||||
	struct sock *ssk;
 | 
						struct sock *ssk;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -701,14 +701,13 @@ static int mptcp_setsockopt_sol_ip_set_transparent(struct mptcp_sock *msk, int o
 | 
				
			||||||
		return PTR_ERR(ssk);
 | 
							return PTR_ERR(ssk);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	issk = inet_sk(ssk);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (optname) {
 | 
						switch (optname) {
 | 
				
			||||||
	case IP_FREEBIND:
 | 
						case IP_FREEBIND:
 | 
				
			||||||
		inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
 | 
							inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case IP_TRANSPARENT:
 | 
						case IP_TRANSPARENT:
 | 
				
			||||||
		issk->transparent = inet_sk(sk)->transparent;
 | 
							inet_assign_bit(TRANSPARENT, ssk,
 | 
				
			||||||
 | 
									inet_test_bit(TRANSPARENT, sk));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		release_sock(sk);
 | 
							release_sock(sk);
 | 
				
			||||||
| 
						 | 
					@ -1441,7 +1440,7 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 | 
				
			||||||
	__tcp_sock_set_cork(ssk, !!msk->cork);
 | 
						__tcp_sock_set_cork(ssk, !!msk->cork);
 | 
				
			||||||
	__tcp_sock_set_nodelay(ssk, !!msk->nodelay);
 | 
						__tcp_sock_set_nodelay(ssk, !!msk->nodelay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inet_sk(ssk)->transparent = inet_sk(sk)->transparent;
 | 
						inet_assign_bit(TRANSPARENT, ssk, inet_test_bit(TRANSPARENT, sk));
 | 
				
			||||||
	inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
 | 
						inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue