mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	inet: move ipv6only in sock_common
When an UDP application switches from AF_INET to AF_INET6 sockets, we have a small performance degradation for IPv4 communications because of extra cache line misses to access ipv6only information. This can also be noticed for TCP listeners, as ipv6_only_sock() is also used from __inet_lookup_listener()->compute_score() This is magnified when SO_REUSEPORT is used. Move ipv6only into struct sock_common so that it is available at no extra cost in lookups. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									090cce4263
								
							
						
					
					
						commit
						9fe516ba3f
					
				
					 8 changed files with 18 additions and 18 deletions
				
			
		| 
						 | 
					@ -194,7 +194,7 @@ struct ipv6_pinfo {
 | 
				
			||||||
	                        sndflow:1,
 | 
						                        sndflow:1,
 | 
				
			||||||
				repflow:1,
 | 
									repflow:1,
 | 
				
			||||||
				pmtudisc:3,
 | 
									pmtudisc:3,
 | 
				
			||||||
				ipv6only:1,
 | 
									padding:1,	/* 1 bit hole */
 | 
				
			||||||
				srcprefs:3,	/* 001: prefer temporary address
 | 
									srcprefs:3,	/* 001: prefer temporary address
 | 
				
			||||||
						 * 010: prefer public address
 | 
											 * 010: prefer public address
 | 
				
			||||||
						 * 100: prefer care-of address
 | 
											 * 100: prefer care-of address
 | 
				
			||||||
| 
						 | 
					@ -273,8 +273,8 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
 | 
				
			||||||
	__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
 | 
						__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define __ipv6_only_sock(sk)	(inet6_sk(sk)->ipv6only)
 | 
					#define __ipv6_only_sock(sk)	(sk->sk_ipv6only)
 | 
				
			||||||
#define ipv6_only_sock(sk)	((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk))
 | 
					#define ipv6_only_sock(sk)	(__ipv6_only_sock(sk))
 | 
				
			||||||
#define ipv6_sk_rxinfo(sk)	((sk)->sk_family == PF_INET6 && \
 | 
					#define ipv6_sk_rxinfo(sk)	((sk)->sk_family == PF_INET6 && \
 | 
				
			||||||
				 inet6_sk(sk)->rxopt.bits.rxinfo)
 | 
									 inet6_sk(sk)->rxopt.bits.rxinfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -287,8 +287,8 @@ static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int inet_v6_ipv6only(const struct sock *sk)
 | 
					static inline int inet_v6_ipv6only(const struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return likely(sk->sk_state != TCP_TIME_WAIT) ?
 | 
						/* ipv6only field is at same position for timewait and other sockets */
 | 
				
			||||||
		ipv6_only_sock(sk) : inet_twsk(sk)->tw_ipv6only;
 | 
						return ipv6_only_sock(sk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define __ipv6_only_sock(sk)	0
 | 
					#define __ipv6_only_sock(sk)	0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,7 @@ struct inet_timewait_sock {
 | 
				
			||||||
#define tw_family		__tw_common.skc_family
 | 
					#define tw_family		__tw_common.skc_family
 | 
				
			||||||
#define tw_state		__tw_common.skc_state
 | 
					#define tw_state		__tw_common.skc_state
 | 
				
			||||||
#define tw_reuse		__tw_common.skc_reuse
 | 
					#define tw_reuse		__tw_common.skc_reuse
 | 
				
			||||||
 | 
					#define tw_ipv6only		__tw_common.skc_ipv6only
 | 
				
			||||||
#define tw_bound_dev_if		__tw_common.skc_bound_dev_if
 | 
					#define tw_bound_dev_if		__tw_common.skc_bound_dev_if
 | 
				
			||||||
#define tw_node			__tw_common.skc_nulls_node
 | 
					#define tw_node			__tw_common.skc_nulls_node
 | 
				
			||||||
#define tw_bind_node		__tw_common.skc_bind_node
 | 
					#define tw_bind_node		__tw_common.skc_bind_node
 | 
				
			||||||
| 
						 | 
					@ -131,7 +132,7 @@ struct inet_timewait_sock {
 | 
				
			||||||
	__be16			tw_sport;
 | 
						__be16			tw_sport;
 | 
				
			||||||
	kmemcheck_bitfield_begin(flags);
 | 
						kmemcheck_bitfield_begin(flags);
 | 
				
			||||||
	/* And these are ours. */
 | 
						/* And these are ours. */
 | 
				
			||||||
	unsigned int		tw_ipv6only     : 1,
 | 
						unsigned int		tw_pad0		: 1,	/* 1 bit hole */
 | 
				
			||||||
				tw_transparent  : 1,
 | 
									tw_transparent  : 1,
 | 
				
			||||||
				tw_flowlabel	: 20,
 | 
									tw_flowlabel	: 20,
 | 
				
			||||||
				tw_pad		: 2,	/* 2 bits hole */
 | 
									tw_pad		: 2,	/* 2 bits hole */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,8 @@ struct sock_common {
 | 
				
			||||||
	unsigned short		skc_family;
 | 
						unsigned short		skc_family;
 | 
				
			||||||
	volatile unsigned char	skc_state;
 | 
						volatile unsigned char	skc_state;
 | 
				
			||||||
	unsigned char		skc_reuse:4;
 | 
						unsigned char		skc_reuse:4;
 | 
				
			||||||
	unsigned char		skc_reuseport:4;
 | 
						unsigned char		skc_reuseport:1;
 | 
				
			||||||
 | 
						unsigned char		skc_ipv6only:1;
 | 
				
			||||||
	int			skc_bound_dev_if;
 | 
						int			skc_bound_dev_if;
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct hlist_node	skc_bind_node;
 | 
							struct hlist_node	skc_bind_node;
 | 
				
			||||||
| 
						 | 
					@ -317,6 +318,7 @@ struct sock {
 | 
				
			||||||
#define sk_state		__sk_common.skc_state
 | 
					#define sk_state		__sk_common.skc_state
 | 
				
			||||||
#define sk_reuse		__sk_common.skc_reuse
 | 
					#define sk_reuse		__sk_common.skc_reuse
 | 
				
			||||||
#define sk_reuseport		__sk_common.skc_reuseport
 | 
					#define sk_reuseport		__sk_common.skc_reuseport
 | 
				
			||||||
 | 
					#define sk_ipv6only		__sk_common.skc_ipv6only
 | 
				
			||||||
#define sk_bound_dev_if		__sk_common.skc_bound_dev_if
 | 
					#define sk_bound_dev_if		__sk_common.skc_bound_dev_if
 | 
				
			||||||
#define sk_bind_node		__sk_common.skc_bind_node
 | 
					#define sk_bind_node		__sk_common.skc_bind_node
 | 
				
			||||||
#define sk_prot			__sk_common.skc_prot
 | 
					#define sk_prot			__sk_common.skc_prot
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,11 +55,9 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
 | 
				
			||||||
		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
 | 
							const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
 | 
				
			||||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
		if (tw->tw_family == PF_INET6) {
 | 
							if (tw->tw_family == PF_INET6) {
 | 
				
			||||||
			const struct ipv6_pinfo *np = inet6_sk(sk);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			tw->tw_v6_daddr = sk->sk_v6_daddr;
 | 
								tw->tw_v6_daddr = sk->sk_v6_daddr;
 | 
				
			||||||
			tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
 | 
								tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
 | 
				
			||||||
			tw->tw_ipv6only = np->ipv6only;
 | 
								tw->tw_ipv6only = sk->sk_ipv6only;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		/* Linkage updates. */
 | 
							/* Linkage updates. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,7 +298,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 | 
				
			||||||
			tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
 | 
								tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
 | 
				
			||||||
			tw->tw_tclass = np->tclass;
 | 
								tw->tw_tclass = np->tclass;
 | 
				
			||||||
			tw->tw_flowlabel = np->flow_label >> 12;
 | 
								tw->tw_flowlabel = np->flow_label >> 12;
 | 
				
			||||||
			tw->tw_ipv6only = np->ipv6only;
 | 
								tw->tw_ipv6only = sk->sk_ipv6only;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,7 +197,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
 | 
				
			||||||
	np->mcast_hops	= IPV6_DEFAULT_MCASTHOPS;
 | 
						np->mcast_hops	= IPV6_DEFAULT_MCASTHOPS;
 | 
				
			||||||
	np->mc_loop	= 1;
 | 
						np->mc_loop	= 1;
 | 
				
			||||||
	np->pmtudisc	= IPV6_PMTUDISC_WANT;
 | 
						np->pmtudisc	= IPV6_PMTUDISC_WANT;
 | 
				
			||||||
	np->ipv6only	= net->ipv6.sysctl.bindv6only;
 | 
						sk->sk_ipv6only	= net->ipv6.sysctl.bindv6only;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Init the ipv4 part of the socket since we can have sockets
 | 
						/* Init the ipv4 part of the socket since we can have sockets
 | 
				
			||||||
	 * using v6 API for ipv4.
 | 
						 * using v6 API for ipv4.
 | 
				
			||||||
| 
						 | 
					@ -294,7 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 | 
				
			||||||
		/* Binding to v4-mapped address on a v6-only socket
 | 
							/* Binding to v4-mapped address on a v6-only socket
 | 
				
			||||||
		 * makes no sense
 | 
							 * makes no sense
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (np->ipv6only) {
 | 
							if (sk->sk_ipv6only) {
 | 
				
			||||||
			err = -EINVAL;
 | 
								err = -EINVAL;
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -371,7 +371,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 | 
				
			||||||
	if (addr_type != IPV6_ADDR_ANY) {
 | 
						if (addr_type != IPV6_ADDR_ANY) {
 | 
				
			||||||
		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
 | 
							sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
 | 
				
			||||||
		if (addr_type != IPV6_ADDR_MAPPED)
 | 
							if (addr_type != IPV6_ADDR_MAPPED)
 | 
				
			||||||
			np->ipv6only = 1;
 | 
								sk->sk_ipv6only = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (snum)
 | 
						if (snum)
 | 
				
			||||||
		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
 | 
							sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
		if (optlen < sizeof(int) ||
 | 
							if (optlen < sizeof(int) ||
 | 
				
			||||||
		    inet_sk(sk)->inet_num)
 | 
							    inet_sk(sk)->inet_num)
 | 
				
			||||||
			goto e_inval;
 | 
								goto e_inval;
 | 
				
			||||||
		np->ipv6only = valbool;
 | 
							sk->sk_ipv6only = valbool;
 | 
				
			||||||
		retv = 0;
 | 
							retv = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1058,7 +1058,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPV6_V6ONLY:
 | 
						case IPV6_V6ONLY:
 | 
				
			||||||
		val = np->ipv6only;
 | 
							val = sk->sk_ipv6only;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPV6_RECVPKTINFO:
 | 
						case IPV6_RECVPKTINFO:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,6 @@ static unsigned int udp6_ehashfn(struct net *net,
 | 
				
			||||||
int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 | 
					int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
 | 
						const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
 | 
				
			||||||
	int sk_ipv6only = ipv6_only_sock(sk);
 | 
					 | 
				
			||||||
	int sk2_ipv6only = inet_v6_ipv6only(sk2);
 | 
						int sk2_ipv6only = inet_v6_ipv6only(sk2);
 | 
				
			||||||
	int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr);
 | 
						int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr);
 | 
				
			||||||
	int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
 | 
						int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
 | 
				
			||||||
| 
						 | 
					@ -95,7 +94,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (addr_type == IPV6_ADDR_ANY &&
 | 
						if (addr_type == IPV6_ADDR_ANY &&
 | 
				
			||||||
	    !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
 | 
						    !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED))
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sk2_rcv_saddr6 &&
 | 
						if (sk2_rcv_saddr6 &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue