diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 27 | 
1 files changed, 25 insertions, 2 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c66b90f71c9..5a439e9a4c0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -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),  |