mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: ipv6: fix TCP early demux
IPv6 needs a cookie in dst_check() call. We need to add rx_dst_cookie and provide a family independent sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									b5497eeb37
								
							
						
					
					
						commit
						5d299f3d3c
					
				
					 7 changed files with 41 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -369,6 +369,7 @@ struct ipv6_pinfo {
 | 
			
		|||
	__u8			rcv_tclass;
 | 
			
		||||
 | 
			
		||||
	__u32			dst_cookie;
 | 
			
		||||
	__u32			rx_dst_cookie;
 | 
			
		||||
 | 
			
		||||
	struct ipv6_mc_socklist	__rcu *ipv6_mc_list;
 | 
			
		||||
	struct ipv6_ac_socklist	*ipv6_ac_list;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
 | 
			
		|||
	int	    (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
 | 
			
		||||
	void	    (*send_check)(struct sock *sk, struct sk_buff *skb);
 | 
			
		||||
	int	    (*rebuild_header)(struct sock *sk);
 | 
			
		||||
	void	    (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
 | 
			
		||||
	int	    (*conn_request)(struct sock *sk, struct sk_buff *skb);
 | 
			
		||||
	struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
 | 
			
		||||
				      struct request_sock *req,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
 | 
			
		|||
	return flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *dst = skb_dst(skb);
 | 
			
		||||
 | 
			
		||||
	dst_hold(dst);
 | 
			
		||||
	sk->sk_rx_dst = dst;
 | 
			
		||||
	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif	/* _INET_SOCK_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 | 
			
		|||
{
 | 
			
		||||
	struct tcp_sock *tp = tcp_sk(sk);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(sk->sk_rx_dst == NULL))
 | 
			
		||||
		inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
 | 
			
		||||
	/*
 | 
			
		||||
	 *	Header prediction.
 | 
			
		||||
	 *	The code loosely follows the one in the famous
 | 
			
		||||
| 
						 | 
				
			
			@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
 | 
			
		|||
	tcp_set_state(sk, TCP_ESTABLISHED);
 | 
			
		||||
 | 
			
		||||
	if (skb != NULL) {
 | 
			
		||||
		inet_sk_rx_dst_set(sk, skb);
 | 
			
		||||
		icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
 | 
			
		||||
		security_inet_conn_established(sk, skb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 | 
			
		|||
				sk->sk_rx_dst = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (unlikely(sk->sk_rx_dst == NULL))
 | 
			
		||||
			inet_sk_rx_dst_set(sk, skb);
 | 
			
		||||
 | 
			
		||||
		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
 | 
			
		||||
			rsk = sk;
 | 
			
		||||
			goto reset;
 | 
			
		||||
| 
						 | 
				
			
			@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
 | 
			
		|||
	.twsk_destructor= tcp_twsk_destructor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *dst = skb_dst(skb);
 | 
			
		||||
 | 
			
		||||
	dst_hold(dst);
 | 
			
		||||
	sk->sk_rx_dst = dst;
 | 
			
		||||
	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct inet_connection_sock_af_ops ipv4_specific = {
 | 
			
		||||
	.queue_xmit	   = ip_queue_xmit,
 | 
			
		||||
	.send_check	   = tcp_v4_send_check,
 | 
			
		||||
	.rebuild_header	   = inet_sk_rebuild_header,
 | 
			
		||||
	.sk_rx_dst_set	   = inet_sk_rx_dst_set,
 | 
			
		||||
	.conn_request	   = tcp_v4_conn_request,
 | 
			
		||||
	.syn_recv_sock	   = tcp_v4_syn_recv_sock,
 | 
			
		||||
	.net_header_len	   = sizeof(struct iphdr),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 | 
			
		|||
		struct tcp_sock *oldtp = tcp_sk(sk);
 | 
			
		||||
		struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
 | 
			
		||||
 | 
			
		||||
		inet_sk_rx_dst_set(newsk, skb);
 | 
			
		||||
		newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb);
 | 
			
		||||
 | 
			
		||||
		/* TCP Cookie Transactions require space for the cookie pair,
 | 
			
		||||
		 * as it differs for each connection.  There is no need to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 | 
			
		|||
		opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
 | 
			
		||||
 | 
			
		||||
	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
 | 
			
		||||
		struct dst_entry *dst = sk->sk_rx_dst;
 | 
			
		||||
 | 
			
		||||
		sock_rps_save_rxhash(sk, skb);
 | 
			
		||||
		if (dst) {
 | 
			
		||||
			if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
 | 
			
		||||
			    dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
 | 
			
		||||
				dst_release(dst);
 | 
			
		||||
				sk->sk_rx_dst = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
 | 
			
		||||
			goto reset;
 | 
			
		||||
		if (opt_skb)
 | 
			
		||||
| 
						 | 
				
			
			@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
 | 
			
		|||
			struct dst_entry *dst = sk->sk_rx_dst;
 | 
			
		||||
			struct inet_sock *icsk = inet_sk(sk);
 | 
			
		||||
			if (dst)
 | 
			
		||||
				dst = dst_check(dst, 0);
 | 
			
		||||
				dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
 | 
			
		||||
			if (dst &&
 | 
			
		||||
			    icsk->rx_dst_ifindex == inet6_iif(skb))
 | 
			
		||||
			    icsk->rx_dst_ifindex == skb->skb_iif)
 | 
			
		||||
				skb_dst_set_noref(skb, dst);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
 | 
			
		|||
	.twsk_destructor= tcp_twsk_destructor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *dst = skb_dst(skb);
 | 
			
		||||
	const struct rt6_info *rt = (const struct rt6_info *)dst;
 | 
			
		||||
 | 
			
		||||
	dst_hold(dst);
 | 
			
		||||
	sk->sk_rx_dst = dst;
 | 
			
		||||
	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
 | 
			
		||||
	if (rt->rt6i_node)
 | 
			
		||||
		inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct inet_connection_sock_af_ops ipv6_specific = {
 | 
			
		||||
	.queue_xmit	   = inet6_csk_xmit,
 | 
			
		||||
	.send_check	   = tcp_v6_send_check,
 | 
			
		||||
	.rebuild_header	   = inet6_sk_rebuild_header,
 | 
			
		||||
	.sk_rx_dst_set	   = inet6_sk_rx_dst_set,
 | 
			
		||||
	.conn_request	   = tcp_v6_conn_request,
 | 
			
		||||
	.syn_recv_sock	   = tcp_v6_syn_recv_sock,
 | 
			
		||||
	.net_header_len	   = sizeof(struct ipv6hdr),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue