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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Eric Dumazet
				Eric Dumazet